前言
一直記得ArrayList的初始容量大小是10,今天再次看ArrayList的源碼(版本:Jdk 7u80)時(shí)發(fā)現(xiàn)在構(gòu)造函數(shù)的注釋上寫著初始化容量是10,但是構(gòu)造函數(shù)中卻沒有指定初始容量,僅僅初始化了一個(gè)空的數(shù)組。應(yīng)該是不知道在哪個(gè)版本中已經(jīng)修改了,我卻還記著之前從別人口里得來的一句話:初始容量是10。實(shí)際上初始容量已經(jīng)是0了,寫出來分享下,有錯(cuò)的地方煩請(qǐng)指出來,說的不一定對(duì)。
測(cè)試
寫了下代碼來測(cè)試下,ArrayList中沒有直接獲取capacity的方法,只能通過反射獲取elementData數(shù)組的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;
}
}
}
結(jié)果如下:
capacity: 0 size: 0
capacity: 10 size: 1
capacity: 11 size: 0
分析
上面結(jié)果也可以看出來,確實(shí)是初始容量為0了。接著看下ArrayList的源碼(下面所有源碼版本為Jdk 7u80):
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
super();
this.elementData = EMPTY_ELEMENTDATA;
}
源碼中這注釋確實(shí)很誤導(dǎo)人,構(gòu)造函數(shù)中沒有初始化大小。但是現(xiàn)在這樣有個(gè)問題,數(shù)組大小為0, 我怎么添加元素進(jìn)去?應(yīng)該就是在add的時(shí)候初始化,繼續(xù)跟進(jìn)add方法的源碼:
public boolean add(E e) {
// 如果剛初始化ArrayList,size肯定是0
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
add方法中第一步先確保容量夠用,這里面有可能就是初始化容量的方法,繼續(xù)跟進(jìn)ensureCapacityInternal的源碼:
private void ensureCapacityInternal(int minCapacity) {
// 由上一步知道m(xù)inCapacity為1
// 這里if的條件也一定為true
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 經(jīng)過上一步之后,minCapacity就等于DEFAULT_CAPACITY,即10。
ensureExplicitCapacity(minCapacity);
}
繼續(xù)跟進(jìn)ensureExplicitCapacity源碼:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// minCapacity此時(shí)為10,if條件成立
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
繼續(xù)跟進(jìn)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:
// 這里就是數(shù)組初始化為10的地方了
elementData = Arrays.copyOf(elementData, newCapacity);
}
源碼跟到這里就算完了,確實(shí)是在add的時(shí)候初始化容量為10。
結(jié)論
ArrayList的初始化容量已經(jīng)變了,不再是以前的10了,而是初始化為0,等到第一次add的時(shí)候再初始化為10。
做這樣的改動(dòng),就是延遲初始化ArrayList的實(shí)際容量,應(yīng)該是考慮到空間的問題,如果一開始就初始化為10,這個(gè)大小為10的數(shù)組中就全部是存的null,如果數(shù)量多了,這個(gè)也是很大的空間。應(yīng)該是這樣的原因吧。