重要屬性
//初次擴容(size為0)時的默認容量
private static final int DEFAULT_CAPACITY = 10;
//存在常量池的零值
private static final Object[] EMPTY_ELEMENTDATA = {};
//實際存儲對象的數(shù)組颤陶,文檔管他叫array buffer
//容量就是指elementData的長度
private transient Object[] elementData;
//數(shù)組最大值是2147483639颗管,不是2147483647的原因是
//有些虛擬機在創(chuàng)建數(shù)組時會有頭部信息
//超過這個值會報OutOfMemoryError
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
初始擴容
- 如果容量從0到1,比如調(diào)用add(E e),會將數(shù)組elementData變成{obj,null,null,null,null,null,null,null,null,null}
- 如果容量從0到12(超過了DEFAULT_CAPACITY )滓走,比如調(diào)用addAll(Collection<? extends E>c)添加一個長度為12的數(shù)組垦江,那么elementData的長度就是12
超過10后的擴容
如果容量超過10,再次擴容時比較,至少需要的容量和1.5當前容量搅方,取大值比吭。至少需要的容量指實際元素的個數(shù)(size的值)。比如當前容量15姨涡,實際元素12衩藤,需要一次性添加4個元素,那么至少需要的容量是16绣溜,1.5當前容量是22慷彤,容量將變?yōu)?2。
代碼實現(xiàn)
//以下三個函數(shù)用來確認是否需要擴容
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//計算擴容值的函數(shù)
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
//分配容量的函數(shù)
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
trimToSize方法
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = Arrays.copyOf(elementData, size);
}
}
由于擴容后會產(chǎn)生很多填充的null怖喻,這個方法可以講這些null都去掉以節(jié)省內(nèi)存底哗,做法是調(diào)用一次copyOf方法創(chuàng)建一個新數(shù)組再把原來的拷貝進去。
總結(jié)
注意到copyOf方法會重新創(chuàng)建一個新的newLength長度的Object[]锚沸,并調(diào)用native方法來將原數(shù)組復制到新的Object[]里跋选,這個動作開銷還是很大的。這也就是數(shù)組擴容邏輯的意義:盡量減少調(diào)用這個copyOf方法哗蜈,從而提高效率前标。