ArrayList擴容機制
首先看下ArrayList是如何初始化的:
- 無參構造器
//ArrayList定義的一個空數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//Arraylist的數據存儲數組
transient Object[] elementData;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
可以看到ArrayList在使用無參構造器初始化時數據存儲數組默認是空,然後我們調用下add()方法看下會發生什麼:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
首先會執行ensureCapacityInternal()方法,繼續跟進看下這個方法是做什麼的:
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//判斷存儲數據的數組是否爲空
//若爲空返回默認長度和自增長度的較大值
//不爲空則返回自增長度
//默認長度DEFAULT_CAPACITY=10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//判斷minCapacity和數據存儲數組的長度大小
//若大於則執行grow()方法並傳入minCapacity
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* ArrayList擴容的關鍵方法
*/
private void grow(int minCapacity) {
// overflow-conscious code
//當前數據存儲數組的長度
int oldCapacity = elementData.length;
//擴容後的數組長度,是oldCapacity加oldCapacity 右移1位的長度和
int newCapacity = oldCapacity + (oldCapacity >> 1);
//比較新的容量和傳入最小容量大小
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//比較新容量和定義的數組最大值大小
//ArrayList定義的數組最大值爲MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//返回int類型的最大值
newCapacity = hugeCapacity(minCapacity);
//執行復制數組方法,並指定新的長度
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
- 當使用有參構造器構建ArrayList對象時:
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//容量大於0時,初始化數據存儲對象elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//等於0時和調用無參構造器一樣
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
其他的步驟就都和上面的一樣了,這裏就不再多說。
ArrayList的擴容機制暫時可以說到這裏了,其實從源碼來看還是比較易懂的。這中間有兩個遺留問題需要留意下:
- 在擴容中有一個成員變量modCount,這個變量的具體作用是什麼?
- ArrayList中定義的數組最大值爲什麼是 Integer.MAX_VALUE - 8,代碼給出的註釋是
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
翻譯過來就是
/**
*要分配的數組的最大大小。
*一些vm在數組中保留一些頭字。
*嘗試分配較大的數組可能會導致
*OutOfMemory錯誤:請求的數組大小超過了虛擬機限制
*/
這兩個問題留待之後研究下。
如果上面說的有哪裏不對,歡迎各位指出,不勝感激!