ArrayList擴容機制

ArrayList擴容機制


首先看下ArrayList是如何初始化的:

  1. 無參構造器
//ArrayList定義的一個空數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//Arraylist的數據存儲數組
transient Object[] elementData;

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

可以看到ArrayList在使用無參構造器初始化時數據存儲數組默認是空,然後我們調用下add()方法看下會發生什麼:

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

首先會執行ensureCapacityInternal()方法,繼續跟進看下這個方法是做什麼的:

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
private static int calculateCapacity(Object[] elementData, int minCapacity) {
		//判斷存儲數據的數組是否爲空
		//若爲空返回默認長度和自增長度的較大值
		//不爲空則返回自增長度
		//默認長度DEFAULT_CAPACITY=10
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;


    //判斷minCapacity和數據存儲數組的長度大小
    //若大於則執行grow()方法並傳入minCapacity
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * ArrayList擴容的關鍵方法
 */
private void grow(int minCapacity) {
        // overflow-conscious code
        //當前數據存儲數組的長度
        int oldCapacity = elementData.length;
        //擴容後的數組長度,是oldCapacity加oldCapacity 右移1位的長度和
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //比較新的容量和傳入最小容量大小
        if (newCapacity - minCapacity < 0)	
            newCapacity = minCapacity;
         //比較新容量和定義的數組最大值大小
         //ArrayList定義的數組最大值爲MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        	//返回int類型的最大值
            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;
    }
  1. 當使用有參構造器構建ArrayList對象時:
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
        	//容量大於0時,初始化數據存儲對象elementData
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
        	//等於0時和調用無參構造器一樣
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

其他的步驟就都和上面的一樣了,這裏就不再多說。

ArrayList的擴容機制暫時可以說到這裏了,其實從源碼來看還是比較易懂的。這中間有兩個遺留問題需要留意下:

  1. 在擴容中有一個成員變量modCount,這個變量的具體作用是什麼?
  2. ArrayList中定義的數組最大值爲什麼是 Integer.MAX_VALUE - 8,代碼給出的註釋是
/**
     * 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
     */

翻譯過來就是

/**

*要分配的數組的最大大小。

*一些vm在數組中保留一些頭字。

*嘗試分配較大的數組可能會導致

*OutOfMemory錯誤:請求的數組大小超過了虛擬機限制

*/

這兩個問題留待之後研究下。

如果上面說的有哪裏不對,歡迎各位指出,不勝感激!

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