java1.8之ArrayList集合源碼解析

成員變量源碼

// 默認的初始化容量
private static final int DEFAULT_CAPACITY = 10;

// 用於空實例的共享空數組實例
private static final Object[] EMPTY_ELEMENTDATA = {};

//用於默認大小的空實例的共享空數組實例。我們將其與空元素數據區分開來,以瞭解何時充氣添加第一個元素。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
 * 存儲ArrayList元素的數組緩衝區。ArrayList的容量是這個數組緩衝區的長度。當添加第一個元素時,任何 
 * 帶//有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList都將擴展爲 
 *  DEFAULT_CAPACITY。
*/
transient Object[] elementData;  // 非私有以簡化嵌套類訪問
/**
 * ArrayList的大小(它包含的元素的數量)
*/
private int size;

構造方法1:

第一種構造方法:
/**
     * 構造具有指定初始容量的list
     *
     * @param  list的初始化容量
     * @throws 如果指定的初始容量是負數就拋出IllegalArgumentException異常
     */
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
               // 如果初始化容量大於0則創建一個容量爲initialCapacity的動態數組
            this.elementData = new Object[initialCapacity];

        } else if (initialCapacity == 0) {
                // 如果初始化容量等於0則設置爲初始化的成員變量EMPTY_ELEMENTDATA空數組
            this.elementData = EMPTY_ELEMENTDATA;

        } else {
                // 如果小於零則拋出非法參數異常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }


第二種構造方法:

/**
  * 源碼註釋:創建一個初始化爲10的list
  * 但是DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一個空的數組,這就是1.8的不點,其實它是在調用add 
  * 方法時添加第一個元素的時候纔將list集合的初始化容量改爲了10,一開始創建集合的時候它的初始化 
  * 容量是0
*/
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }


第三種構造方法:
/**
     *構造包含指定的集合
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws
     */
    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;
        }
    }

我們來看看add()方法:到底是不是在第一次添加元素的時候才完成的初始化容量;


    public boolean add(E e) {

        // 確定內部容量。size代表的是list中已有的元素length
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    *此方法是上面方法中calculateCapacity的實現方法,在此方法中,if判斷只有在第二種構造方法new 
     ArrayList()才能判斷通過,通過後初識化爲(DEFAULT_CAPACITY = 10)

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    // 否則返回
        return minCapacity;
    }

    
    *此方法是上面方法中ensureExplicitCapacity的實現方法

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

        // 這裏就是判斷需不需要擴容,如果當前集合長度大於底層數組長度則進行擴容,進而調用下面的 
        // grow()方法
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    
// grow()方法的實現
private void grow(int minCapacity) {
        // 把數組長度賦值給老的容量
        int oldCapacity = elementData.length;

        // 新的數組容量 = 老的數組容量的1.5倍  oldCapacity >>1 相當於除以2
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        
        // 如果新的容量小於傳入的參數容量,則新的容量等於傳入的參數容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        
        // 如果新的容量大於數組容納的最大元素個數 MAX_ARRAY_SIZE 2^{31}-1-8
        // 那麼在判斷傳入的容量是否大於數組容納的最大元素個數,如果大於的話,那麼新的數組容量則等於
        // Integer.MAX_VALUE;否則等於 MAX_ARRAY_SIZE

        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

這裏有3個判斷:

if (newCapacity - minCapacity < 0)
if (newCapacity - MAX_ARRAY_SIZE > 0)
以及hugeCapacity(minCapacity);函數中的:
(minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
意義爲:當重新計算的容量(x1.5那個計算)小於傳入要求容量參數,那麼新的容量則按照新傳入的容量爲基準;

當傳入容量參數太大,大到超過了數組的容量限定值2^{31}-1-8卻又小於整數限定值 2^{31}-1,那麼新的數組容量以整數限定值 2^{31}-1爲準,但是當傳入的容量參數不大於數組的容量限定值時,以容量限定值2^{31}-1-8爲準;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章