ArrayList在日常用的還挺多的,用起來十分舒服,順手。這裏來學習一下它的源碼。java
下面是類的定義:數組
1 public class ArrayList<E> extends AbstractList<E> 2 implements List<E>, RandomAccess, Cloneable, java.io.Serializable { 3 4 }
實現的接口還挺多的。dom
首先來看下一ArrayList的幾個屬性:學習
1. DEFAULT_CAPACITY:初始容量this
1 private static final int DEFAULT_CAPACITY = 10;
DEFAULT_CAPACITY,是ArrayList的初始容量,有意思是它使用的時機。spa
2. EMPTY_ELEMENTDATA:共享的空數組.net
1 private static final Object[] EMPTY_ELEMENTDATA = {};
英文註釋是:"Shared empty array instance used for empty instances."。這個看上去仍是很好理解的,可是下面還有一個屬性也是空數組。code
3. DEFAULTCAPACITY_EMPTY_ELEMENTDATA:默認容量的空數組對象
好奇怪,用一個EMPTY_ELEMENTDATA不就能夠了麼,爲何還要用一個DEFAULTCAPACITY_EMPTY_ELEMENTDATA呢?當咱們使用new ArrayList()的時候就會發現這個空數組實例排上用場了:blog
1 public ArrayList() { 2 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 3 }
這個方法的英文註釋是:"Constructs an empty list with an initial capacity of ten."。可是這裏其實就把這個空的數組對象DEFAULTCAPACITY_EMPTY_ELEMENTDATA給了elementData,並無實例化額外的對象數組。
4. elementData:實際元素所在的數組
1 transient Object[] elementData; // non-private to simplify nested class access
elementData纔是元素真正存放的地方,這裏不明白的是爲何要用transient關鍵字。
這個數組緩衝區是ArrayList存儲元素的地方。ArrayList的容量正是這個數組緩衝區的長度。任何elementData爲DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList會在添加第一個元素的時候,將容量擴充到DEFAULT_CAPACITY(目前是10)。
5. size:數組中元素的長度
1 private int size;
這裏的size並非elementData數組的長度,而是這個數組真正包含的元素的個數(這個個數其實有待商榷,後面會講到)。
在ArrayList中一共有3個構造方法:
1 // 給定初始容量 2 public ArrayList(int initialCapacity); 3 4 // 空參構造方法 5 public ArrayList(); 6 7 // 從其餘集合類中構造 8 public ArrayList(Collection<? extends E> c);
1. 給定初始容量的constructor
1 public ArrayList(int initialCapacity) { 2 if (initialCapacity > 0) { 3 this.elementData = new Object[initialCapacity]; 4 } else if (initialCapacity == 0) { 5 this.elementData = EMPTY_ELEMENTDATA; 6 } else { 7 throw new IllegalArgumentException("Illegal Capacity: "+ 8 initialCapacity); 9 } 10 }
邏輯以下:
惟一一點是爲啥這個時候要用EMPTY_ELEMENTDATA了,而不是繼續用原來的DEFAULTCAPACITY_EMPTY_ELEMENTDATA了。
2. 空參構造方法
1 public ArrayList() { 2 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 3 }
這個就比較簡單了,和上面對比的是,這個時候爲啥要用DEFAULTCAPACITY_EMPTY_ELEMENTDATA?
問題來了:new ArrayList(0)和new ArrayList()有啥不一樣呢?
惟一的不一樣就在於內部數組用的不是同一個,雖然它們都是空的。
3. 從集合類中構造
1 public ArrayList(Collection<? extends E> c) { 2 elementData = c.toArray(); // 注意, 這個時候ArrayList中元素的順序取決於toArray 3 if ((size = elementData.length) != 0) { 4 // c.toArray might (incorrectly) not return Object[] (see 6260652) 5 if (elementData.getClass() != Object[].class) 6 elementData = Arrays.copyOf(elementData, size, Object[].class); 7 } else { 8 // replace with empty array. 9 this.elementData = EMPTY_ELEMENTDATA; 10 } 11 }
這裏有兩個地方須要注意下:
Collection接口的toArray方法依賴於實現類中的具體實現,有時候ArrayList中的順序對咱們來講仍是挺重要的。而後在來看一下,這個官方bug,我在網上查了一下,發現這篇寫的不錯:https://blog.csdn.net/gulu_gulu_jp/article/details/51457492。
新增元素的方法是ArrayList中最值得關注的,它提供了兩種add方法:
沒有index的add方法
1 public boolean add(E e) { 2 ensureCapacityInternal(size + 1); // Increments modCount!! 3 elementData[size++] = e; 4 return true; 5 }
ensureCapacityInternal方法在ArrayList中不少地方都用到了,很是關鍵的方法。
當插入新元素所需的最小capacity要比內部數組的長度大的時候,就要擴容了,如今原來的基礎之上擴容50%,若是新的capacity比最小的capacity還要小的話,直接用所需最小的capacity做爲capacity。
有index的方法
在這種狀況下是在ArrayList的某個位置上插入一個元素,而後把index後邊的元素集體往右移一位。須要注意的問題是,index的範圍是有限制的,必須在[0, size)之間,那麼這中檢查是爲了避免讓ArrayList之間出現空洞。
1 public void add(int index, E element) { 2 rangeCheckForAdd(index); // 返回檢查 3 ensureCapacityInternal(size + 1); // 擴容 4 System.arraycopy(elementData, index, elementData, index + 1, 5 size - index); // 右移元素 6 elementData[index] = element; // 插入新元素 7 size++; 8 }
理解了ArrayList的內部模型的話,其實看不看源碼感受關係不大。
其餘方法我以爲還挺常規的,沒有太多好說的,就是System.arraycopy用得還挺多的,專門用於複製數組。
以上~