首先看方法聲明:java
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
RandomAccess:數組
public interface RandomAccess { }
RandomAccess
接口都是給 List所使用的,用來代表其支持快速(一般是固定時間)隨機訪問,爲其提供良好的性能。實際經驗證實,若是是下列狀況,則 List
實現應該實現此接口,即對於典型的類實例而言,此循環:多線程
for (int i=0, n=list.size(); i < n; i++) list.get(i);
的運行速度要快於如下循環:併發
for (Iterator i=list.iterator(); i.hasNext(); ) i.next();
Cloneable:app
public interface Cloneable { }
實現了此接口的類就能夠經過重寫 Object.clone()
方法來定製對其進行復制的細節,若是在沒有實現 Cloneable
接口的實例上調用 Object
的 clone
方法,則會致使拋出 CloneNotSupportedException
異常。dom
/** * ArrayList中元素存儲的地方,數組的長度就是它的容量 */ private transient Object[] elementData; /** *ArrayList所包含的元素的大小 */ private int size;
提供了3種構造方法:工具
public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } public ArrayList() { this(10); } public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }
能夠看到:第一種方法須要一個默認的容量大小,第二個是默認的構造方法,會默認建立一個容量爲10的 ArrayList
,第三個則傳給一個 Collection
,注意,無論 Collection
裏面是什麼類型,最後放進 ArrayList
都會上轉爲 Object
性能
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
add
方法中使用了 ensureCapacityInternal
來控制容量:測試
private void ensureCapacityInternal(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
其中 modCount
是用來記錄 list被結構修改的次數,所謂結構上的修改是 指任何添加或刪除一個或多個元素的操做,或者顯式調整底層數組的大小
;僅僅設置元素的值不是結構上的修改;在上面的方法中,若是 minCapacity
大於現有數組長度,則執行 grow
方法:this
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; /*newCapacity 擴展爲舊容量的1.5倍左右*/ int newCapacity = oldCapacity + (oldCapacity >> 1); /*若是這時新容量還小於minCapacity,則新容量爲minCapacity*/ if (newCapacity - minCapacity < 0) newCapacity = minCapacity; /*新容量大於 Integer.MAX_VALUE - 8*/ if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 最後將原數組放進新數組,改變長度 elementData = Arrays.copyOf(elementData, newCapacity); }
若是 newCapacity
大於 Integer.MAX_VALUE - 8
,則 newCapacity
爲 Integer.MAX_VALUE
,這也是可以擴充的最大容量
再來看第二種 add
方法:
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
這種方法是在指定位置插入元素,主要使用了 System.arraycopy()
方法將 index
以後的元素向後移動一個位置,將 index
位空出來放入新元素
clear
方法比較簡單,可是注意調用 clear
也會使 modCount
加1:
public void clear() { modCount++; // Let gc do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
public Object clone() { try { @SuppressWarnings("unchecked") ArrayList<E> v = (ArrayList<E>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } }
clone
方法只能進行淺複製,並不複製元素自己
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }
remove
方法中,若是要移除的元素爲 null
,則刪除數組中第一個爲 null
的元素。若是數組中有超過一個匹配的元素,僅移除第一個
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
這個方法被不少方法使用,它調用了 Arrays
工具類中的方法 copyOf
:
public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); }
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
最終調用了方法:
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
它的參數列表以下:
src - 源數組。
srcPos - 源數組中的起始位置。
dest - 目標數組。
destPos - 目標數據中的起始位置。
length - 要複製的數組元素的數量。
從指定源數組中複製一個數組,複製從指定的位置開始,到目標數組的指定位置結束。這個方法是一個 native
方法,而且經測試,若是是引用數組類型,它不會真正複製對象,只是複製引用(淺複製)
將此 ArrayList
實例的容量調整爲列表的當前大小。應用程序能夠使用此操做來最小化 ArrayList
實例的存儲量。
public void trimToSize() { modCount++; int oldCapacity = elementData.length; if (size < oldCapacity) { elementData = Arrays.copyOf(elementData, size); } }
由此可知:在 ArrayList
容量肯定下來之後,能夠調用這個方法最小化存儲空間
此類的 iterator
和 listIterator
方法返回的迭代器是快速失敗的:在建立迭代器以後,除了經過迭代器自身的 remove
或 add
方法從結構上對列表進行修改,不然在任什麼時候間以任何方式對列表進行修改,迭代器都會拋出 ConcurrentModificationException
。所以,面對併發的修改,迭代器很快就會徹底失敗,而不是冒着在未來某個不肯定時間發生任意不肯定行爲的風險。
注意,迭代器的快速失敗行爲沒法獲得保證,快速失敗迭代器會盡最大努力拋出 ConcurrentModificationException
。迭代器的快速失敗行爲應該僅用於檢測 bug。
前面說到 ArrayList
中定義了一個 modCount
來記錄對容器進行結構修改的次數,在 add
、 addAll
、 remove
、 clear
、 clone
方法中都會引發 modCount
變化,而在建立迭代器時,會使用局部變量保存當前的 modCount
值:
private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; ...
在進行迭代的過程當中,會先檢查 modCount
有沒有發生變化,以此來斷定是否有外部操做改變了容器:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
最後,由於 ArrayList
是非同步的,所以,在多線程環境下,若是有對容器進行結構修改的操做,則必須使用外部同步。