Java8集合框架——ArrayList源碼分析

 java.util.ArrayList

如下爲主要介紹要點,從 Java 8 出發:html

 

1、ArrayList的特色概述

  從ArrayList自己特色出發,結論以下:java

關注點 ArrayList相關結論

是否容許空的元素面試

是否容許重複的元素

元素有序:讀取數據和存放數據的順序一致數組

是否線程安全
隨機訪問的效率 隨機訪問指定索引(即數組的索引)的元素快
順序添加元素的效率

在不涉及擴容時,順序添加元素速度快;安全

當須要擴容時,涉及到元素的複製,相對較慢多線程

刪除和插入元素的效率

因涉及到複製和移動後續的元素,相對較慢app

  

2、ArrayList的內部實現:從內部屬性和構造函數提及

  ArrayList是一個內部以數組方式實現列表、能夠自動擴容的集合。其內部實現有5個重要的屬性,源碼以下:dom

    /**
     * Default initial capacity.
     * 默認的初始化元素個數(容量),使用ArrayList()建立時(即不指定容量),首次添加元素會進行
     * 內部數組的首次擴容,擴容容量就是DEFAULT_CAPACITY = 10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     * 用於構造空實例時的默認共享空數組,在使用 ArrayList(0) (即指定容量爲0)或者
     * ArrayList(Collection<? extends E> c)且c.size()=0 (即便用空集合來建立),
     * 就會使用該空數組做爲默認的空實例
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     * 另外一個共享的空數組,使用ArrayList()時默認的空實現,區別於上面的EMPTY_ELEMENTDATA,
     * 用來判斷添加第一個元素時是否須要按照默認的容量DEFAULT_CAPACITY進行擴容.
     * 其餘有指定初始容量的ArrayList(即使大小是0),涉及到的擴容便按照默認的規則進行
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     * 實際存儲列表元素的數組。這也是讀取數據和存放數據的順序一致、隨機訪問指定元素、
     * 順序添加元素快(在末尾添加,且不涉及擴容的狀況下)的緣由。
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     * 數組中元素的實際個數
     * @serial
     */
    private int size;
    
    /**
     * 用於記錄被修改(增長/刪除/修改等)的次數
     */
    protected transient int modCount = 0;
    

 

  ArrayList有3個常規的構造函數。ide

1. 空參構造函數函數

  直接使用共享空數組:DEFAULTCAPACITY_EMPTY_ELEMENTDATA 。

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

  這裏註釋寫着構造一個初始容量爲10的空數組??? 其實意思是說,經過這個構造函數創建的ArrayList,初始容量都是10,而初始容量則是在第1次添加元素時進行擴容的。後續的添加元素的源碼中,能夠看到正是經過  elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA  來將默認容量設置爲10的。

2. 指定初始容量的構造函數

  比較簡單的按照初始容量構造內部數組,或者是默認的共享空數組(指定初始容量爲0時) EMPTY_ELEMENTDATA

    /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

3. 經過指定的集合進行構造

  一樣當指定集合的大小爲0時,也會默認爲共享空數組 EMPTY_ELEMENTDATA

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

  

3、ArrayList添加元素和擴容

源碼以下:

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

  add(E e) 調用了 ensureCapacityInternal(size + 1) 來判斷容量是否知足,首先判斷是不是默認的 DEFAULTCAPACITY_EMPTY_ELEMENTDATA ,如果則說明建立的時候沒有指定容量,此時按照默認容量DEFAULT_CAPACITY = 10 進行首次擴容(size + 1 = 1)。而 ensureCapacityInternal(size + 1)調用了ensureExplicitCapacity(minCapacity) 再一次進行判斷,這個方法記錄了總共進行修改過的次數modCount,同時進行了實際的數組擴容。固然只有實際數組元素個數size超過數組長度時纔會進行擴容。

  從這裏能夠看到,若是原先有指定初始容量,那麼後續的擴容都按照原始的容量來進行的,與默認容量10就沒有關係了。

    // 沒有指定初始容量時,按照默認的 DEFAULT_CAPACITY 進行擴容
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 實際超過數組長度纔會進行擴容
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

  擴容的方法以下。對於沒有溢出的,實際的擴容是原來的1.5倍,這裏使用了位運算,右移一位相似與/2操做,取了一半,可是位操做快。這裏須要說明的是,默認空構造器時創建的ArrayList也是在這裏首次進行擴容的,使用默認容量 DEFAULT_CAPACITY = 10

  這裏擴容後還須要將原來的元素複製到新的位置中,所以說涉及到的擴容的改動操做都會比較耗時。

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

 

   elementData[size++] = e;就是直接的元素賦值,而後增長 size 的大小。

  另外還有指定索引添加元素的,代碼以下。總結來講大體步驟以下:

  1. 判斷邊界
  2. 擴容
  3. 從指定索引處開始的元素都日後移動一位
  4. 插入指定索引的指定元素,size加1,完成。

  從這裏能夠看出,因涉及到複製和移動其餘的元素,插入元素比較慢。刪除也是相似的。 

    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

    從這兩處源碼能夠看到,ArrayList並無判斷元素是什麼,而是直接存儲了,所以說:ArrayList容許空的或者重複的元素。

4、ArrayList刪除元素

刪除元素有2類:

  1. 指定索引刪除元素
  2. 指定元素刪除:這裏找到第一個equals或者null(如元素爲null)便可

1. 指定索引刪除元素

  1. 邊界判斷
  2. modCount++
  3. 記錄指定索引的舊元素
  4. 非最後一個元素,即size - index - 1 > 0,把元素前移一個單位。
  5. 清空最後一個索引元素
  6. 返回舊元素

源碼以下。這裏邊界檢查只作了 >= size,由於數組元素自己不會超過size的,而使用 < 0 的index時,對於elementData(index),自己就是IndexOutOfBound的,並不須要直接判斷。

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
    /**
     * Checks if the given index is in range.  If not, throws an appropriate
     * runtime exception.  This method does *not* check if the index is
     * negative: It is always used immediately prior to an array access,
     * which throws an ArrayIndexOutOfBoundsException if index is negative.
     */
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

  

2. 指定元素刪除

  刪除的步驟相似,只是這裏是遍歷找到第一個指定的元素而已,而後一樣須要進行後面元素的前遷。

    /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

    /*
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

 

5、ArrayList查找和修改元素

1. 按照指定索引查找元素

  這裏只作了邊界檢查,若是沒有越界,直接返回指定索引的元素便可,所以說速度比較快。

    /**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

 2. 按照指定索引修改元素

  指定索引修改元素,按照索引,速度也是比較快。

    /**
     * Replaces the element at the specified position in this list with
     * the specified element.
     *
     * @param index index of the element to replace
     * @param element element to be stored at the specified position
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

6、ArrayList的遍歷和出現的問題

  幾種遍歷方式:for循環(按照索引下標)、迭代器遍歷、forEach遍歷。

一、for循環(按照索引下標)

  這裏就是簡單地經過 get(i) 來獲取,略。。。

二、迭代器遍歷 Iterator

  Iterator 是各類集合類中比較標準的訪問方式,它隱藏了各類集合的內部結構,抽象出統一的訪問方式。迭代器自己3個比較重要的接口以下:

    /**
     * Returns {@code true} if the iteration has more elements.
     * (In other words, returns {@code true} if {@link #next} would
     * return an element rather than throwing an exception.)
     *
     * @return {@code true} if the iteration has more elements
     */
    boolean hasNext();

    /**
     * Returns the next element in the iteration.
     *
     * @return the next element in the iteration
     * @throws NoSuchElementException if the iteration has no more elements
     */
    E next();

    /**
     * Removes from the underlying collection the last element returned
     * by this iterator (optional operation).  This method can be called
     * only once per call to {@link #next}.  The behavior of an iterator
     * is unspecified if the underlying collection is modified while the
     * iteration is in progress in any way other than by calling this
     * method.
     *
     * @implSpec
     * The default implementation throws an instance of
     * {@link UnsupportedOperationException} and performs no other action.
     *
     * @throws UnsupportedOperationException if the {@code remove}
     *         operation is not supported by this iterator
     *
     * @throws IllegalStateException if the {@code next} method has not
     *         yet been called, or the {@code remove} method has already
     *         been called after the last call to the {@code next}
     *         method
     */
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

   具體到ArrayList,調用其 iterator() 方法,返回的則是內部類 Itr 。

    /**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

   下面看看 Itr 如何處理上面貼出來的3個接口的。

  首先默認 cursor = 0,從索引 0 處進行元素的遍歷沒有問題。而元素的最大索引是 size - 1,所以在 hasNext()  中經過 cursor != size 來判斷是否還有下一個元素或者說遍歷結束。另外這裏還記錄了modCount,在後續中會經過此變量的變化來判斷在遍歷過程當中,當前集合是否被修改過,從而拋出 ConcurrentModificationException (fail-fast機制)。

    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return,下一個要返回的元素的索引
        int lastRet = -1; // index of last element returned; -1 if no such,上一個返回的索引的索引
        int expectedModCount = modCount;    // 用於檢查判斷是否有過修改

        public boolean hasNext() {
            return cursor != size;// size表示數組實際元素數量,cursor == size表示已經遍歷結束
        }
    }

   接下來看看 next() 方法,它返回當前須要遍歷的元素,若是在調用前當前集合被修改過並且以前記錄的 expectedModCount 沒有被修改過,也即就是 modCount != expectedModCount,則會拋出 ConcurrentModificationException 。

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();
        // 判斷索引是否已經越界
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        // cursor移動1位
        cursor = i + 1;
        // 返回實際的索引,同時記錄已返回的下標lastRet
        return (E) elementData[lastRet = i];
    }
    // 檢查在遍歷過程當中,當前集合是否被修改過
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }

   而當中只有調用 remove() 纔會從新對expectedModCount進行更新,並且也只有調用這裏的 remove 進行元素的移除才能保證安全。

    public void remove() {
        // 沒有先調用next()而先調用remove()明顯是不行的,此時lastRet = -1會直接拋出異常
        if (lastRet < 0)
            throw new IllegalStateException();
        // 檢查當前集合是否被修改過
        checkForComodification();

        try {
            // 實際上仍是調用ArrayList自己的remove
            ArrayList.this.remove(lastRet);
            // 當前集合已經移除了一個元素,對crusor進行復位
            cursor = lastRet;
            // lastRet進行復位,確保下一次remove前判斷有效
            lastRet = -1;
            // 從新記錄modCount
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

 三、forEach遍歷

  這裏 forEach 也只是遍歷獲取elementData[i] ,固然內部會有一些判斷,確保不會越界並且是否會有 ConcurrentModificationException 異常,有必定地安全性。

    @Override
    public void forEach(Consumer<? super E> action) {
        // 例行地非空判斷
        Objects.requireNonNull(action);
        // 記錄modCount,同時使用final標識說明不容許修改
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        // 每次獲取元素前都須要判斷是否索引正常/modCount正常
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            action.accept(elementData[i]);
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

四、遍歷出現的問題

   在 for 循環中遍歷集合的時候使用 remove 會有什麼問題呢?例子以下,例子1 中因爲有實時判斷邊界,所以並無出錯,而例子2 因爲中途進行了 remove 操做而致使 List 的 size 發生變化了,而原來記錄的 size 並無進行更新,再次進行 remove ,rangeCheck即可檢測出越界異常。

    // 例子1:沒有報錯
    List<String> strList1 = new ArrayList<>();
    strList1.add("1");
    strList1.add("2");
    strList1.add("3");
    strList1.add("3");
    for (int i = 0; i < strList1.size(); i++) {
        if ("3".equals(strList1.get(i))) {
            strList1.remove(i);    // remove以後,i++爲3,此時strList1.size()也爲3,正確退出不出錯
        }
    }
    System.out.println(strList1);

    // 例子2:Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
    List<String> strList2 = new ArrayList<>();
    strList2.add("1");
    strList2.add("2");
    strList2.add("3");
    strList2.add("3");
    int size = strList2.size();    // 4
    for (int i = 0; i < size; i++) {
        if ("3".equals(strList2.get(i))) {
            strList2.remove(i);    // remove以後,i = 2,而size仍爲4,i++爲3,仍然知足條件,而此時就越界了
        }
    }
    System.out.println(strList2);

 

五、ConcurrentModificationException異常

  迭代器中屢次提到了 ConcurrentModificationException 異常,固然也只有在 modCount 和 expectedModCount 不一致時纔會這樣。那何時會出現不一致呢:使用集合的 add 或者 remove 就會改變 modCount ,製造出機會。多線程或者單線程下進行模擬操做均可以,下面舉個單線程例子:

    List<String> itrList = new ArrayList<>();
    itrList.add("1");
    itrList.add("2");
    itrList.add("3");
    itrList.add("4");
    Iterator<String> iterator = itrList.iterator();
    while (iterator.hasNext()) {
        String nextStr = iterator.next();
        if ("3".equals(nextStr)) {
            // 操做1:正常不會報錯???
            // itrList.remove("3");
            // 操做2:正常不會報錯
            iterator.remove();
        }
        if ("2".equals(nextStr)) {
            // 操做3:Exception in thread "main" java.util.ConcurrentModificationException
            // itrList.remove("2");
        }
    }
    System.out.println(itrList);

 

   其中操做2沒有拋出異常能夠理解,畢竟 iterator 自己的 remove 會考慮到 expectedModCount 的修正。可是操做1和操做3一樣是使用集合自己的 remove,可是操做3如期拋出了異常,而操做1並無。其實,操做1中進行remove以後,iterator 內部的 cursor = 3,且 cursor == size,此時 iterator.hasNext() 中 cursor != size 返回 false,所以退出了,而操做3則還會繼續,所以 checkForComodification 時即可檢查出 ConcurrentModificationException。更多可參考 :Java ConcurrentModificationException異常緣由和解決方法

六、ConcurrentModificationException異常的一道面試題

  網上copy過來的1道題,這裏拋出來的異常是 IndexOutOfBoundsException 而並不是 ConcurrentModificationException。

  其中的 testList.iterator().hasNext() 每次都是返回一個新的 iteraror ,在進行 testList.remove 以後,新的modCount 便賦給了新的 iteraror,並且也沒有對新的 iteraror 進行什麼操做;而 i++ 卻逐漸累計,testList.size() 逐漸變小,當進行到 i = 5 時,實際上 size = 5,此時 testList.remove(5) 便拋出瞭如期的 IndexOutOfBoundsException。

    ArrayList<String> testList = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        testList.add("sh" + i);
    }
    for (int i = 0; testList.iterator().hasNext(); i++) {
        testList.remove(i);
        System.out.println("test" + testList.get(i));
    }
    // Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 5, Size: 5 

  

7、ArrayList的內部元素elementData爲什麼用transient修飾

  ArrayList自己實現了CloneableSerializable,可是關鍵的成員變量倒是用了transient進行了修飾,不但願被序列化。

1 public class ArrayList<E> extends AbstractList<E>
2         implements List<E>, RandomAccess, Cloneable, java.io.Serializable

   從序列化的實現來看,只對elementData中有元素的部分進行了序列化,並無所有元素,這是合理的,通常elementData的容量比實際的size大,沒有必要全部元素都行序列化。這也提升了時間效率,同時節省了空間。

 1     /**
 2      * Save the state of the <tt>ArrayList</tt> instance to a stream (that
 3      * is, serialize it).
 4      *
 5      * @serialData The length of the array backing the <tt>ArrayList</tt>
 6      *             instance is emitted (int), followed by all of its elements
 7      *             (each an <tt>Object</tt>) in the proper order.
 8      */
 9     private void writeObject(java.io.ObjectOutputStream s)
10         throws java.io.IOException{
11         // Write out element count, and any hidden stuff
12         int expectedModCount = modCount;
13         s.defaultWriteObject();
14 
15         // Write out size as capacity for behavioural compatibility with clone()
16         s.writeInt(size);
17 
18         // Write out all elements in the proper order.
19         for (int i=0; i<size; i++) {
20             s.writeObject(elementData[i]);
21         }
22 
23         if (modCount != expectedModCount) {
24             throw new ConcurrentModificationException();
25         }
26     }

 8、ArrayList和Vector的比較

       一、Vector是線程安全的:Vector大部分方法都和ArrayList差很少,可是其實現都添加了synchronized來保證操做的安全性。

       二、Vector能夠指定擴容的增加因子capacityIncrement,每次須要擴容時會根據擴容因子進行判斷,直接擴展指定的因子,或者是倍增,以下:

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

 

9、Java8中ArrayList的部分改動說明 

  相比Java7,Java8中增長了 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 並做爲默認空構造器時的空實現,而原來的 EMPTY_ELEMENTDATA 則改成在 指定容量且容量爲0 或者 指定初始化的集合而集合大小也爲0 時的空實現。

 1     /**
 2      * Shared empty array instance used for empty instances.
 3      */
 4     private static final Object[] EMPTY_ELEMENTDATA = {};
 5 
 6     /**
 7      * Shared empty array instance used for default sized empty instances. We
 8      * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 9      * first element is added.
10      */
11     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
相關文章
相關標籤/搜索