一、簡介
ArrayList是基於數組實現的一個動態數組,其容量能自動增長。ArrayList不是線程安全的,多線程環境下考慮Collections.synchronizedList(List l)函數返回一個線程安全的ArrayList類,也可以使用concurrent併發包下的CopyOnWriteArrayList類。
二、源碼理解
2.1 類繼承關係
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList繼承AbstractList抽象父類,實現了List接口(規定了List的操作規範)、RandomAccess(可隨機訪問)、Cloneable(可拷貝)、Serializable(可序列化)
2.2 類屬性
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//序列化版本號
private static final long serialVersionUID = 8683452581122892189L;
//默認數組容量
private static final int DEFAULT_CAPACITY = 10;
//空實例,默認爲{},通過帶參數構造器創建實例時使用
static final Object[] EMPTY_ELEMENTDATA = {};
//缺省空實例,採用ArrayList默認大小10創建的空實例
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//用來存儲真正的數據數組
transient Object[] elementData;
//數組元素數量
private int size;
//最大數組容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}
2.3 構造函數
-
有參構造器(初始化數組容量)
public ArrayList(int initialCapacity) { //如果initialCapacity大於0則根據指定的大小創造一個數組 if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; //如果initialCapacity等於0則將默認的空列表EMPTY_ELEMENTDATA賦值給elementData } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; //小於0則拋出參數異常 } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
-
無參構造器
public ArrayList() { //將DEFAULTCAPACITY_EMPTY_ELEMENTDATA空數組賦值給elementData this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
-
有參構造器(根據給定的集合)
public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { //如果elementData長度不等於0,並且不是Object類型數組時,則調用Arrays.copyOf複製一個Object類型數組,並複製給elementData if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { //如果數組大小等於0,則將EMPTY_ELEMENTDATA空數組賦值給elementData this.elementData = EMPTY_ELEMENTDATA; } }
2.4 核心函數
-
add(E e):添加元素
public boolean add(E e) { //調用ensureCapacityInternal函數,確定數組的大小,size+1表示添加當前元素後數組的容量大小 ensureCapacityInternal(size + 1); //將數組size位置的元素設置爲e elementData[size++] = e; return true; }
private void ensureCapacityInternal(int minCapacity) { //如果數組是默認的空數組,則將minCapacity與默認數組的容量大小比較,取最大的賦值給minCapacity(需要的數組容量值) if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //確定是否需要數組擴容 ensureExplicitCapacity(minCapacity); }
private void ensureExplicitCapacity(int minCapacity) { //記錄集合的修改次數 modCount++; //如果需要的數組容量大小大於當前數組大小,則調用grow()方法進行擴容 if (minCapacity - elementData.length > 0) grow(minCapacity); }
//這個方法是ArrayList這個類add方法的最後一步,主要做的就是確定size然後進行數組的copy與賦值 //至於真正的copy,是由Arrays.copyOf調用System.arraycopy,最後完成copy這一步是個native方法去做的 private void grow(int minCapacity) { int oldCapacity = elementData.length; //newCapacity當前數組容量,取原數組的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //如果暫定數組容量不滿足指定容量minCapacity,則將minCapacity賦值給newCapacity if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果newCapacity大於最大容量,則調用hugeCapacity()方法確定最終值 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //調用Arrays.copyOf(原數組,數組大小),將數組copy形成新的數組重新複製,從而完成數組的擴容 elementData = Arrays.copyOf(elementData, newCapacity); }
//超容量數組大小判斷 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); //如果minCapacity 大於MAX_ARRAY_SIZE則取Integer的最大值,如果小於則取MAX_ARRAY_SIZE return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
通過add方法的閱讀可以發現,幾個重要的點
- ArrayList本質上是個數組,數據存儲是由數組來完成,ArrayList只不過是進行了封裝、擴展功能
- 數組容量最大爲Integer的最大值
- 添加元素內部實現,其實是建立的新的數組,所以再創建ArrayList時最好有個預估容量大小,不然會造成頻繁的擴容