ArrayList原理分析(重點在於擴容)
阿新 • • 發佈:2018-12-07
首先,ArrayList定義只定義類兩個私有屬性:
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. */ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * *View Code@serial */ private int size;
可知:elementData儲存ArrayList內的元素,size表示它包含的元素的數量(不是指容量)。
注意:elementData用transient修飾,這表明當持久化ArrayList物件時,並不會儲存它。
ArrayList是基於陣列實現的,新增元素時,將某個位置的值設定為指定元素即可,但陣列容量不夠,如何擴容呢?
我們提供具體的方法來分析:
add方法:
// 將指定的元素新增到此列表的尾部。 public booleanView Codeadd(E e) { ensureCapacity(size + 1); //判斷容量是否足夠,不夠就擴容 elementData[size++] = e; return true; }
那麼擴容的核心在於ensureCapacity方法
ensureCapacity方法:
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length;View Codeif (minCapacity > oldCapacity) { //size+1即新增後的長度,判斷如果新增,會不會過長 Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; //1.5倍擴容 if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); //將老陣列拷貝一份到新陣列 } }
可知:
1. 每次新增前都會判斷是否會過長,會,則先擴容
2. 每次擴容都是1.5倍擴容,其實是1.5倍+1。
3. 老陣列通過Arrays.copyOf()拷貝一份到新陣列
那麼問題來了,每次擴容都是1.5倍是否會造成較大的空間浪費?
是的,所以建議在構造ArrayList例項時,就預估大小並指定其容量,以避免陣列擴容的發生。或者根據實際需求,直接呼叫ensureCapacity方法來手動增加ArrayList例項的容量。