首先看一下無參的構造方法: 在未指定容量大小時,會將final的DEFAULTCAPACITY_EMPTY_ELEMENTDATA給elementData,這樣的好處是無論多少次實例化無參ArrayList初始的保存對象都是固定的,而不必每次都創建一個新的Object數組. 這樣需要在每次做添加操作 ...
首先看一下無參的構造方法:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
在未指定容量大小時,會將final的DEFAULTCAPACITY_EMPTY_ELEMENTDATA給elementData,這樣的好處是無論多少次實例化無參ArrayList初始的保存對象都是固定的,而不必每次都創建一個新的Object數組.
這樣需要在每次做添加操作時調用方法ensureCapacityInternal(int):
private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_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); } 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); }
在每次調用添加操作時都會驗證是否未指定容量大小的實例化,這裡的DEFAULT_CAPACITY=10,也就是說,當不指定容量大小時,第一次添加操作會給list的容量設為10.
提及一下modCount這個屬性,它是用作保存對list修改操作的次數。它的值常常用在iterator中,在遍歷前會保存它的值,在每次next(),remove()中都回去比較modCount是否改變,改變了就會拋出ConcurrentModificationException.
grow()用於增加list的容量,該方法中第二行也可寫成:
int newCapacity = oldCapacity * 3 / 2;
但位運算的速度比乘除的速度要快很多.
有容量參數構造方法顯得簡單很多:
public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }