版權聲明:本文爲博主原創文章,轉載請註明出處,歡迎交流學習!java
ArrayList底層維護的是一個動態數組,每一個ArrayList實例都有一個容量。該容量是指用來存儲列表元素的數組的大小。它老是至少等於列表的大小。隨着向 ArrayList 中不斷添加元素,其容量也自動增加。數組
ArrayList不是同步的(也就是說不是線程安全的),若是多個線程同時訪問一個ArrayList實例,而其中至少一個線程從結構上修改了列表,那麼它必須保持外部同步,在多線程環境下,可使用Collections.synchronizedList方法聲明一個線程安全的ArrayList,例如:安全
List arraylist = Collections.synchronizedList(new ArrayList());多線程
下面經過ArrayList的源碼來分析其原理。app
一、ArrayList的構造方法:ArrayList提供了三種不一樣的構造方法學習
1) ArrayList(),構造一個初始容量爲 10 的空列表。this
2) ArrayList(int initialCapacity),構造一個具備指定初始容量的空列表。spa
3) ArrayList(Collection<? extends E> c),構造一個包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的。線程
源碼以下:對象
private transient Object[] elementData;
public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; //生成一個長度爲10的Object類型的數組 } public ArrayList() { this(10); //調用ArrayList(int i) }
public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); //返回包含此 collection 中全部元素的數組 size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); //複製指定的數組,返回包含相同元素和長度的Object類型的數組 }
當採用不帶參數的構造方法ArrayList()生成一個集合對象時,實際上是在底層調用ArrayList(int initialCapacity)這一構造方法生產一個長度爲10的Object類型的數組。當採用帶有集合類型參數的構造方法時,在底層生成一個包含相同的元素和長度的Object類型的數組。
二、add方法:ArrayList提供了兩種添加元素的add方法
1) add(E e),將指定的元素添加到此列表的尾部。
2) add(int index, E e),將指定的元素插入此列表中的指定位置。向右移動當前位於該位置的元素(若是有)以及全部後續元素(將其索引加 1)。
public boolean add(E e) { ensureCapacity(size + 1); // 擴大數組容量 elementData[size++] = e; //將元素e添加到下標爲size的Object數組中,而且執行size++ return true; }
public void add(int index, E element) { if (index > size || index < 0) //若是指定要插入的數組下標超過數組容量或者指定的下標小於0,拋異常 throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); ensureCapacity(size+1); // 擴大數組容量 System.arraycopy(elementData, index, elementData, index + 1,size - index); //從指定源數組中複製一個數組,複製從指定的位置開始,到目標數組的指定位置結束。
// elementData --- 源數組 index --- 源數組中的起始位置
// elementData --- 目標數組 index+1 --- 目標數組中的起始位置
// size - index --- 要複製的數組元素的數量 elementData[index] = element; //將要添加的元素放到指定的數組下標處 size++; }
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; //原數組的容量 if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; //定義新數組的容量,爲原數組容量的1.5倍+1 if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); //複製指定的數組,返回新數組的容量爲newCapacity } }
若是集合中添加的元素超過了10個,那麼ArrayList底層會新生成一個數組,長度爲原數組的1.5倍+1,並將原數組中的元素copy到新數組中,而且後續添加的元素都會放在新數組中,當新數組的長度沒法容納新添加的元素時,重複該過程。這就是集合添加元素的實現原理。
三、get方法:
1) get(int index),返回此列表中指定位置上的元素。
public E get(int index) { RangeCheck(index); //檢查傳入的指定下標是否合法 return (E) elementData[index]; //返回數組下標爲index的數組元素 } private void RangeCheck(int index) { if (index >= size) //若是傳入的下標大於或等於集合的容量,拋異常 throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); }
四、remove方法:
1) E remove(int index),移除此列表中指定位置上的元素。向左移動全部後續元素(將其索引減 1)。
2) boolean remove(Object o),移除此列表中首次出現的指定元素(若是存在)。若是列表不包含此元素,則列表不作改動,返回boolean值。
public E remove(int index) { RangeCheck(index); //檢查指定的下標是否合法 modCount++; E oldValue = (E) elementData[index]; //獲取指定下標的數組元素 int numMoved = size - index - 1; //要移動的元素個數 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //移動數組元素 elementData[--size] = null; // Let gc do its work return oldValue; } public boolean remove(Object o) { if (o == null) { //若是傳入的參數爲null for (int index = 0; index < size; index++) if (elementData[index] == null) { //移除首次出現的null fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; } private void fastRemove(int index) { //移除指定位置的元素,實現方法相似remove(int i) modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work }
五、clone方法:
1) Object clone(),返回此ArrayList實例的淺表副本(不復制這些元素自己) 。
public Object clone() { try { ArrayList<E> v = (ArrayList<E>) super.clone(); //調用Object類的clone方法返回一個ArrayList對象 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(); } }
以上經過對ArrayList部分關鍵源碼的分析,知道了ArrayList底層的實現原理,關於ArrayList源碼有如下幾點幾點總結:
1) ArrayList 底層是基於數組來實現的,能夠經過下標準確的找到目標元素,所以查找的效率高;可是添加或刪除元素會涉及到大量元素的位置移動,效率低。
2) ArrayList提供了三種不一樣的構造方法,無參數的構造方法默認在底層生成一個長度爲10的Object類型的數組,當集合中添加的元素個數大於10,數組會自動進行擴容,即生成一個新的數組,並將原數組的元素放到新數組中。
3) ensureCapacity方法對數組進行擴容,它會生成一個新數組,長度是原數組的1.5倍+1,隨着向ArrayList中不斷添加元素,當數組長度沒法知足須要時,重複該過程。