1. 程式人生 > >Java集合--ArrayList源碼

Java集合--ArrayList源碼

快速 add 最重要的 incr fir tca ava 分析 好的

ArrayList是Java的動態數組集合,主要用於快速讀取數組元素,且在讀多寫少的情況下具有較好的表現;相比於LinedList,更節省空間,因為LinkedList的元素還要多存儲前後繼節點的指針,相較於ArrayList只存儲元素本身有一定的差距,但是ArrayList在使用不當的時候也容易浪費內存,例如大量數據不斷寫入ArrayList時,會不斷分配新的內存,並復制原有數據到新的內存中。

1  /**
2      * The array buffer into which the elements of the ArrayList are stored.
3      * The capacity of the ArrayList is the length of this array buffer. Any
4 * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 5 * will be expanded to DEFAULT_CAPACITY when the first element is added. 6 */ 7 transient Object[] elementData; // non-private to simplify nested class access

elementData數組是ArrayList最重要的屬性之一,用於存儲實際的數據;elementData為什麽會被定義為transient關鍵字修飾呢?因為ArrayList多數情況下會出現空余數組空間,如果序列化全部的數組,那麽會造成時間和空間的額外消耗;ArrayList提供了自己的writeObject方法和readObject方法,只序列化了實際存儲的元素。

 /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

size是elementData數組中實際存儲的元素的個數,區別於elementData.length,在ArrayList中,elementData數組的長度是ArrayList的實際開辟空間的長度

 /**
     * This helper method split out from add(E) to keep method
     * bytecode size under 35 (the -XX:MaxInlineSize default value),
     * which helps when add(E) is called in a C1-compiled loop.
     
*/ private void add(E e, Object[] elementData, int s) { if (s == elementData.length) elementData = grow(); //grow()方法擴充開辟新空間,並復制數據到新空間 elementData[s] = e; size = s + 1; } /** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ public boolean add(E e) { modCount++; add(e, elementData, size); return true; }

從add(E e)方法中可以分析出,數組中當前元素的個數等於數組的長度時,會增長當前數組的長度;

/**
     * 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
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

    private Object[] grow() {
        return grow(size + 1);
    }

/**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by 50% if that suffices.
     * Will not return a capacity greater than MAX_ARRAY_SIZE unless
     * the given minimum capacity is greater than MAX_ARRAY_SIZE.
     *
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

擴充數組容量時,會成倍增長,如果數據量較大又未開辟足夠的空間,且不斷寫入新數據的時候,ArrayList需要不斷開辟新空間又要復制數據,性能較差且可能浪費內存空間;

在add(),set(),remove()等寫方法中,會看到modCount得增加,這個字段有什麽作用呢?在AbstractList中能看到modCount的定義

 /**
     * The number of times this list has been <i>structurally modified</i>.
     * Structural modifications are those that change the size of the
     * list, or otherwise perturb it in such a fashion that iterations in
     * progress may yield incorrect results.
     *
     * <p>This field is used by the iterator and list iterator implementation
     * returned by the {@code iterator} and {@code listIterator} methods.
     * If the value of this field changes unexpectedly, the iterator (or list
     * iterator) will throw a {@code ConcurrentModificationException} in
     * response to the {@code next}, {@code remove}, {@code previous},
     * {@code set} or {@code add} operations.  This provides
     * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
     * the face of concurrent modification during iteration.
     *
     * <p><b>Use of this field by subclasses is optional.</b> If a subclass
     * wishes to provide fail-fast iterators (and list iterators), then it
     * merely has to increment this field in its {@code add(int, E)} and
     * {@code remove(int)} methods (and any other methods that it overrides
     * that result in structural modifications to the list).  A single call to
     * {@code add(int, E)} or {@code remove(int)} must add no more than
     * one to this field, or the iterators (and list iterators) will throw
     * bogus {@code ConcurrentModificationExceptions}.  If an implementation
     * does not wish to provide fail-fast iterators, this field may be
     * ignored.
     */
    protected transient int modCount = 0;

modCount用來記錄鏈表被修改的次數;典型的場景是:當叠代器對鏈表操作時,其他方法修改了該鏈表,那麽通過對比modCount的值就可以判斷鏈表在使用的時候是否被修改過,如果被修改過,立即拋出ConcurrentModificationException異常。這就是AbstractList的fail-fast機制,而不是出現不確定的行為。

final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

checkForComodification()方法定義在ArrayList的私有內部類中,叠代器常用的next方法和remove方法都會調用該方法,用於快速檢測鏈表是否被其他行為修改

Java集合--ArrayList源碼