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,如果數量多了,這個也是很大的空間。應該是這樣的原因吧。