1. 程式人生 > 其它 >ArrayList原始碼分析-自動擴容機制

ArrayList原始碼分析-自動擴容機制

ArrayList類:
public class ArrayList....{

......

private static final int DEFAULT_CAPACITY = 10; //預設容量 10
transient Object[] elementData; //存放元素的陣列
private int size;  //實際元素個數
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //沒有元素時的預設容量 也就是 0

...... }
無參構造
    public ArrayList() {
        
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
通過構造方法可以知道,新建立的 ArrayList 容量是0,size=0
以add方法為入口分析 ArrayList 的複製寬容機制:
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
add方法成功時返回true,過程呼叫ensureCapacityInternal,新建時size等於0
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

ensureExplicitCapacity 呼叫 ensureExplicitCapacity,傳參 calculateCapacity(elementData, minCapacity)

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

新建時,我們已經看過無參構造中把 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 賦值給 elementData ,所以上面的方法中if條件成立,返回 Math.max(DEFAULT_CAPACITY, minCapacity);

而 DEFAULT_CAPACITY 是10,所以當新建或裝入的元素個數小於10時,都是返回10,當大於10的時候,返回的時minCapacity,而 minCapacity 其實等於 size + 1。

執行完 calculateCapacity,將結果傳入 ensureExplicitCapacity:

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

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

如果元素個數小於10,傳入的數就是10,此時 minCapacity - elementData.length > 0 成立,執行 grow(10)。

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);
}

grow( int minCapacity ) 就是其擴容方法,元素個數小於10時 ,例如 新建時oldCapacity = 0;newCapacity = 0;第一個if成立,newCapacity = 10 ,進入第二個if ,這裡MAX_ARRAY_SIZE 的定義:

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

也就是說MAX_ARRAY_SIZE非常大,對於我們正常開發中的實際情況,第二個if都是不成立的,如果成立將會呼叫hugeCapacity方法,這種情況很少,我們繼續往下:

elementData = Arrays.copyOf(elementData, newCapacity);

執行Arrays.copyOf後elementData 容量從0到了10。

10個以後呢?

帶著size=10,從新走一遍上面的程式碼:

進入add方法後執行:ensureCapacityInternal(10+ 1):

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

先呼叫

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

返回minCapacity,進入ensureExplicitCapacity(11):

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

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

條件11-10>0成立進入 grow(11):

    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);
    }

oldCapacity = 10,newCapacity = 10 + 10/2 = 15;第一個if不成立,第二個條件不成立,執行 Arrays.copyOf方法,elementData完成了複製元素並把容量從10變成15。

總結:

沒有向集合中新增任何元素時:容量0,新增一個元素後容量10,當超過10個後,每次以1.5倍的擴充容量。