ArrayList的初始容量現在為0,不再是10了


前言

一直記得ArrayList的初始容量大小是10,今天再次看ArrayList的源碼(版本:Jdk 7u80)時發現在構造函數的注釋上寫着初始化容量是10,但是構造函數中卻沒有指定初始容量,僅僅初始化了一個空的數組。應該是不知道在哪個版本中已經修改了,我卻還記着之前從別人口里得來的一句話:初始容量是10。實際上初始容量已經是0了,寫出來分享下,有錯的地方煩請指出來,說的不一定對。
測試
寫了下代碼來測試下,ArrayList中沒有直接獲取capacity的方法,只能通過反射獲取elementData數組的size來間接獲取到capacity。代碼如下:

public class ArrayListCapacityTest {

    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        System.out.println("capacity: " + getCapacity(arrayList) + " size: " + arrayList.size());

        arrayList.add("test");
        System.out.println("capacity: " + getCapacity(arrayList) + " size: " + arrayList.size());

        arrayList = new ArrayList(11);
        System.out.println("capacity: " + getCapacity(arrayList) + " size: " + arrayList.size());
        }

    public static int getCapacity(ArrayList arrayList) {
        try {
            Field elementDataField = ArrayList.class.getDeclaredField("elementData");
            elementDataField.setAccessible(true);
            return ((Object[]) elementDataField.get(arrayList)).length;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return -1;
        }
    }
}

結果如下:

capacity: 0 size: 0
capacity: 10 size: 1
capacity: 11 size: 0

分析

上面結果也可以看出來,確實是初始容量為0了。接着看下ArrayList的源碼(下面所有源碼版本為Jdk 7u80):

 /**
  * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}

源碼中這注釋確實很誤導人,構造函數中沒有初始化大小。但是現在這樣有個問題,數組大小為0, 我怎么添加元素進去?應該就是在add的時候初始化,繼續跟進add方法的源碼:

public boolean add(E e) {
    // 如果剛初始化ArrayList,size肯定是0
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

add方法中第一步先確保容量夠用,這里面有可能就是初始化容量的方法,繼續跟進ensureCapacityInternal的源碼:

private void ensureCapacityInternal(int minCapacity) {
    // 由上一步知道minCapacity為1
    // 這里if的條件也一定為true
    if (elementData == EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    // 經過上一步之后,minCapacity就等於DEFAULT_CAPACITY,即10。
    ensureExplicitCapacity(minCapacity);
}

繼續跟進ensureExplicitCapacity源碼:

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

    // overflow-conscious code
    // minCapacity此時為10,if條件成立
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

繼續跟進grow源碼:

private void grow(int minCapacity) {
    // overflow-conscious code
    // oldCapacity = 0
    int oldCapacity = elementData.length;
    // newCapacity = 0
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        // newCapacity由上層傳來為10
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    // 這里就是數組初始化為10的地方了
    elementData = Arrays.copyOf(elementData, newCapacity);
}

源碼跟到這里就算完了,確實是在add的時候初始化容量為10。

結論

ArrayList的初始化容量已經變了,不再是以前的10了,而是初始化為0,等到第一次add的時候再初始化為10。

做這樣的改動,就是延遲初始化ArrayList的實際容量,應該是考慮到空間的問題,如果一開始就初始化為10,這個大小為10的數組中就全部是存的null,如果數量多了,這個也是很大的空間。應該是這樣的原因吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM