ArrayList是Java中比較常用的一個類,它是基于數組實作,非線程安全,可快速随機通路List中的元素。
ArrayList具有動态擴容的機制,每次在添加元素時,都會判斷容量是否夠用,如果不夠用,則需要擴容。
JDK1.8中,ArrayList的初始容量為0,第一次添加元素時,會将容量設定為10,如果容量不夠,則每次會擴大50%
擴容代碼如下:
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
其中:
int newCapacity = oldCapacity + (oldCapacity >> 1);
容量被擴充為原容量的1.5倍,oldCapacity>>1,右移一位,即:oldCapacity除以2
elementData = Arrays.copyOf(elementData, newCapacity);
用Arrays的copyOf方法拷貝原數組内容,并設定新的長度。
可以看到ArrayList擴容需要做一次數組拷貝,如果是反複擴容,肯定會對程式的運作效率産生影響。是以在初始化ArrayList的時候,盡量設定初始化容量,避免其擴容。
測試代碼:
final int count = 20 * 100000;
List<Integer> list = new ArrayList<>();
long begin = System.currentTimeMillis();
for(int i = 0; i < count ; i++) {
list.add(i);
}
System.out.println("沒有設定ArrayList初始容量: " + (System.currentTimeMillis() - begin) + " ms");
list = new ArrayList<>(count);
begin = System.currentTimeMillis();
for(int i = 0; i < count ; i++) {
list.add(i);
}
System.out.println("設定了ArrayList初始容量: " + (System.currentTimeMillis() - begin) + " ms");
執行結果:
沒有設定ArrayList初始容量: 89 ms
設定了ArrayList初始容量: 18 ms