1. 程式人生 > >ArrayList原理分析(重點在於擴容)

ArrayList原理分析(重點在於擴容)

首先,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). 
      * 
      * 
@serial */ private int size;
View Code

可知:elementData儲存ArrayList內的元素,size表示它包含的元素的數量(不是指容量)。

注意:elementData用transient修飾,這表明當持久化ArrayList物件時,並不會儲存它。

 

ArrayList是基於陣列實現的,新增元素時,將某個位置的值設定為指定元素即可,但陣列容量不夠,如何擴容呢?

我們提供具體的方法來分析:

add方法:

// 將指定的元素新增到此列表的尾部。  
    public boolean
add(E e) { ensureCapacity(size + 1); //判斷容量是否足夠,不夠就擴容 elementData[size++] = e; return true; }
View Code

那麼擴容的核心在於ensureCapacity方法

 

ensureCapacity方法:

public void ensureCapacity(int minCapacity) {  
    modCount++;  
    int oldCapacity = elementData.length;  
    
if (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); //將老陣列拷貝一份到新陣列 } }
View Code

可知:

1. 每次新增前都會判斷是否會過長,會,則先擴容

2. 每次擴容都是1.5倍擴容,其實是1.5倍+1

3. 老陣列通過Arrays.copyOf()拷貝一份到新陣列

 

那麼問題來了,每次擴容都是1.5倍是否會造成較大的空間浪費?

是的,所以建議在構造ArrayList例項時,就預估大小並指定其容量,以避免陣列擴容的發生。或者根據實際需求,直接呼叫ensureCapacity方法來手動增加ArrayList例項的容量