ArrayList是咱們很是經常使用的一個集合,那麼ArrayList是如何實現呢?java
ArrayList<String> arrayList = new ArrayList<>(); arrayList.add("Hello"); if (arrayList.contains("Hello")) { System.out.println("[Hello] is in ArrayList!"); } arrayList.remove("Hello");
public ArrayList() { private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //存儲數據的集合 transient Object[] elementData; // non-private to simplify nested class access //.... this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
從構造函數能夠看出,如今咱們的集合是一個空集合,真正存儲數據的數組也是一個長度爲0的數組。數組
public boolean add(E e) { modCount++; add(e, elementData, size); return true; } private void add(E e, Object[] elementData, int s) { //存儲數據的數組已經所有被使用 if (s == elementData.length) //擴張數組 elementData = grow(); elementData[s] = e; size = s + 1; }
一個參數的add方法調用了private的add方法,在該方法中真正完成了向集合中添加元素。在添加元素的時候,若是size==存儲數據的數組的長度,那麼就代表數組已經存滿了,這時候就須要將本來的數組進行擴張,如何擴張數組是經過 grow
方法來實現的。函數
private Object[] grow() { return grow(size + 1); } private Object[] grow(int minCapacity) { //複製當前數組到一個新的數組中(新的數組長度已經擴張過) return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity)); } //計算新的擴張長度 private int newCapacity(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //計算新的容量 //新容量= 數組的長度+數組的長度向右位移1(例如:10>>1 = 5, 11>>1 = 5) //這種新容量的計算方式代表:當集合的長度越大時,集合每一次的擴張的幅度就會愈來愈大 int newCapacity = oldCapacity + (oldCapacity >> 1); //當新容量小於最小容量時,以最小容量爲基準 if (newCapacity - minCapacity <= 0) { //當數組中沒有元素的時候,會執行這個分支 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) //返回最小容量和默認容量中較大的一個 return Math.max(DEFAULT_CAPACITY, minCapacity); if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return minCapacity; } return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity);//極端狀況,能夠不考慮(幾乎不會走到這個分支) } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
Grow 方法是實現ArrayList長度可變的核心,其實現思想是源碼分析
當數組存放滿了的時候,就擴張數組(當集合中的元素的數量越多的時候,擴張的幅度就越大。)
而擴張數組是經過,創建新的數組(長度等於擴張後的長度),而後將舊的數組中的元素填充到新數組中,這種方式來實現的。this
Contains也是ArrayList集合很是經常使用的一個方法,用來判斷集合中是否包含指定的元素。code
public boolean contains(Object o) { return indexOf(o) >= 0; } public int indexOf(Object o) { return indexOfRange(o, 0, size); } int indexOfRange(Object o, int start, int end) { Object[] es = elementData; if (o == null) { for (int i = start; i < end; i++) { if (es[i] == null) { return i; } } } else { for (int i = start; i < end; i++) { if (o.equals(es[i])) { return i; } } } return -1; }
contains方法最終調用了調用了indexOfRange方法,indexOfRange作的工做是,在集合指定的範圍內判斷是否包含指定的元素,若是包含就返回下標,不然就返回-1.ci
public boolean remove(Object o) { final Object[] es = elementData; final int size = this.size; int i = 0; //搜尋指定元素 found: { if (o == null) { for (; i < size; i++) if (es[i] == null) break found; } else { for (; i < size; i++) if (o.equals(es[i])) break found; } return false; } //移除元素 fastRemove(es, i); return true; } private void fastRemove(Object[] es, int i) { modCount++; final int newSize; //若是不是在數組的末尾移除元素 if ((newSize = size - 1) > i) //將i以後全部元素向前移動一個下標 System.arraycopy(es, i + 1, es, i, newSize - i); es[size = newSize] = null; }
remove方法的邏輯很清晰:element
ArrayList經過數組實現了可變集合,可是咱們從源碼中能夠看出來,若是要增長刪除元素的話,是很是消耗資源和時間的(由於在頻繁的操做數組),可是訪問的時候是特別的快的(直接經過下標訪問便可)。資源
能夠得出結論: ArrayList不適合頻繁的增長刪除,可是適合查詢。rem