ArrayList的序列化與擴容
ArrayList的底層實現時陣列,與普通的陣列相比,ArrayList能實現容量的動態增長。在ArrayList中最重要的屬性是: elementData和size。elementData是Object[]的陣列,size是陣列中實際元素的大小。
(一)序列化
可以看到elementData被transient修飾了。transient用來說明elementData並不參與序列化的過程,而ArrayList是實現Serializable介面的,具體的序列化實現在writeObject()方法中,序列化的內容只取實際元素的元素(即size實際大小的元素)以減少io的損耗。
(二)擴容
(1)什麼時候擴容? 以向ArrayList中新增元素的add()方法為例:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } 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); }
可以看到當minCapacity大於elementData的容量時,便開始擴容,而minCapacity是由size+1和DEFAULT_CAPACITY(預設10) 的大者決定的。
(2)擴多大的容?
先看下擴容的程式碼:
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //(tag 1) 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); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
在上面的程式碼中,在tag 1之前newCapacity大小獲取的思路是取minCapacity和oldCapacity擴大1.5倍(oldCapacity >> 1位移運算,計算的結果是oldCapacity的一半)的較大者。之後當newCapacity大於 MAX_ARRAY_SIZE時呼叫hugeCapacity()計算newCapacity新的值。其中MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8。在官方的說明中,減8是因為一些虛擬機器保留頭資訊,減8可以減少出錯的概率。在hugeCapacity中可以看到 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE :MAX_ARRAY_SIZE;,因此陣列擴容後最大值依然為Integer.MAX_VALUE。