1. 程式人生 > >jdk 1.8 Arraylist自動擴容

jdk 1.8 Arraylist自動擴容

以無參構造為例

第一步:呼叫add方法新增元素

public boolean add(E e) {

    ensureCapacityInternal(size + 1);  // 新增元素前先呼叫ensureCapacityInternal方法
    elementData[size++] = e;//新增物件時,size+1
    return true;
}

第二步:呼叫ensureCapacityInternal方法,設定好minCapacity的值

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //判斷是否為空陣列
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

當空陣列新增第1個元素時,minCapacity=1,呼叫max()方法取出DEFAULT_CAPACITY和minCapacity的最大值 ,minCapacity變為DEFAULT_CAPACITY(預設大小10),呼叫ensureExplicitCapacity方法。

當新增第2個元素時,直接呼叫ensureExplicitCapacity方法。

 

第三步:呼叫ensureExplicitCapacity方法修改修改次數,並判斷是否需要擴容

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;//修改次數加1

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);//呼叫擴容方法
}

當新增第1個元素時,此時的elementData.length=1(為空列表),minCapacity=10,所以minCapacity>elementData.length,會進入grow(minCapacity)方法(此時minCapacity=10)。

當新增第2個元素時,此時的minCapacity=2,此時elementData.length(即是容量)在新增第一個元素後擴容成10了,所以minCapacity<elementData.length,不會進入grow(minCapacity)方法,陣列容量仍為10不變

所以當新增第3、4···到第10個元素時,依然不會執行grow方法,陣列容量都為10。

當新增到第11個元素時,(minCapacity=11)>(elementData.length=10),所以進入grow(minCapacity)方法進行擴容。

 

第四步:呼叫grow方法進行擴容

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //通過位運算右移一位,相當於除以2,運算速度快,新容量擴大到原容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        //從minCapacity和newCapacity種取出一個較大值作為擴容後新陣列的容量
        //這個if判斷主要是針對新增第一個元素時使用,1.5倍的oldCapacity 還是為0,所以newCapacity為最小容量10
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        //如果新容量大於陣列的最大size,進入hugeCapacity方法
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //最後將原來的陣列和新的容量大小傳入到copyOf方法中複製(先設定一個新容量大小的陣列,把原資料放入其中即可)
    elementData = Arrays.copyOf(elementData, newCapacity);
}

當add第1個元素時,oldCapacity為0,第一個if成立,newCapacity=minCapacity=10;但是第二個if不成立,則不會進入hugeCapacity方法,陣列容量為10,add方法中return true,size增為1。

當add第11個元素進入grow方法時,newCapacity為15,比minCapacity(為11)大,第一個if判斷不成立。新容量沒有大於陣列最大size,不會進入hugeCapacity方法。陣列容量擴為15,add方法中return true,size增為11。

 

第五步:如果新容量大於MAX_ARRAY_SIZE,進入hugeCapacity方法

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