一、ArrayList 類
這裏分析jdk 1.8,包含一些1.8新特性的源碼
繼承樹如下:
宏觀上說,ArrayList是基於動態數組實現的,數組具有按索引查找的特性,所以訪問很快,適合經常查詢的數據。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
二、ArrayList屬性
//序列號
private static final long serialVersionUID = 8683452581122892189L;
//默認容量
private static final int DEFAULT_CAPACITY = 10;
//一個空數組,當用戶指定該 ArrayList 容量爲 0 時,返回該空數組
private static final Object[] EMPTY_ELEMENTDATA = {};
/*一個空數組實例
* - 當用戶沒有指定 ArrayList 的容量時(即調用無參構造函數),返回的是該數組==>剛創建一個 ArrayList 時,其內數據量爲 0。
* - 當用戶第一次添加元素時,該數組將會擴容,變成默認容量爲 10(DEFAULT_CAPACITY) 的一個數組===>通過 ensureCapacityInternal() 實現
* 它與 EMPTY_ELEMENTDATA 的區別就是:該數組是默認返回的,而後者是在用戶指定容量爲 0 時返回*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList基於數組實現,用該數組保存數據, ArrayList 的容量就是該數組的長度
//該值爲 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 時,當第一次添加元素進入 ArrayList 中時,數組將擴容值
private transient Object[] elementData; //transient:在採用Java默認的序列化機制的時候,被該關鍵字修飾的屬性不會被序列化。
//ArrayList實際存儲的數據數量
private int size;
三、ArrayList構造方法
//創建一個初試容量的、空的ArrayList,當初試容量值非法(小於0)時拋出異常
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
//無參構造函數:創建一個 空的 ArrayList,此時其內數組緩衝區 elementData = {}, 長度爲 0,當元素第一次被加入時,擴容至默認容量 10
public ArrayList() {
super();
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//創建一個包含collection的ArrayList,要放入 ArrayList 中的集合其內元素將會全部添加到新建的 ArrayList 實例中
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); //將集合轉化成Object[]數組
size = elementData.length; //把轉化後的Object[]數組長度賦值給當前ArrayList的size,並判斷是否爲0
// c.toArray might (incorrectly) not return Object[] (see 6260652)
// 這句話意思是:c.toArray 可能不會返回 Object[],可以查看 java 官方編號爲 6260652 的 bug
if (elementData.getClass() != Object[].class) { // 若 c.toArray() 返回的數組類型不是 Object[],則利用 Arrays.copyOf(); 來構造一個大小爲 size 的 Object[] 數組
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 替換空數組
this.elementData = EMPTY_ELEMENTDATA;
}
}
四、ArrayList常用方法
public void trimToSize()
將數組緩衝區大小調整到實際 ArrayList 存儲元素的大小
public void trimToSize() { // modCount 是 AbstractList 的屬性值:protected transient int modCount = 0; // [問] modCount 有什麼用? modCount++; // 當實際大小 < 數組緩衝區大小時 // 如調用默認構造函數後,剛添加一個元素,此時 elementData.length = 10,而 size = 1 // 通過這一步,可以使得空間得到有效利用,而不會出現資源浪費的情況 if (size < elementData.length) { // 注意這裏:這裏的執行順序不是 (elementData = (size == 0) ) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); // 而是:elementData = ((size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size)); // 這裏是運算符優先級的語法 // 調整數組緩衝區 elementData,變爲實際存儲大小 Arrays.copyOf(elementData, size) //先判斷size是否爲0,如果爲0:實際存儲爲EMPTY_ELEMENTDATA,如果有數據就是Arrays.copyOf(elementData, size) elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
public void ensureCapacity(int minCapacity)
指定 ArrayList 的容量
public void ensureCapacity(int minCapacity) { // 最小擴充容量,默認是 10 //這句就是:判斷是不是空的ArrayList,如果是的最小擴充容量10,否則最小擴充量爲0 //上面無參構造函數創建後,當元素第一次被加入時,擴容至默認容量 10,就是靠這句代碼 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; // 若用戶指定的最小容量 > 最小擴充容量,則以用戶指定的爲準,否則還是 10 if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } }
private void ensureCapacityInternal(int minCapacity):明確 ArrayList 的容量,提供給本類使用的方法
private void ensureExplicitCapacity(int minCapacity):明確 ArrayList 的容量,用於內部優化,保證空間資源不被浪費:尤其在 add() 方法添加時起效
private void grow(int minCapacity):擴容,以確保 ArrayList 至少能存儲 minCapacity 個元素
private static int hugeCapacity(int minCapacity):大容量分配,最大分配 Integer.MAX_VALUE
返回ArrayList實際存儲的元素數量
public int size() { return size; }
判斷ArrayList是否有元素
public boolean isEmpty() { return size == 0; }
是否包含o元素
public boolean contains(Object o) { // 根據 indexOf() 的值(索引值)來判斷,大於等於 0 就包含 // 注意:等於 0 的情況不能漏,因爲索引號是從 0 開始計數的 return indexOf(o) >= 0; }
public int indexOf(Object o)
順序查找,返回元素的最低索引值(最首先出現的索引位置)
public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
public int lastIndexOf(Object o)
逆序查找,返回元素的最低索引值(最首先出現的索引位置)
public int lastIndexOf(Object o) { if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; }
public Object clone()
實現的有Cloneable接口,深度複製:對拷貝出來的 ArrayList 對象的操作,不會影響原來的 ArrayList
public Object clone() { try { // Object 的克隆方法:會複製本對象及其內所有基本類型成員和 String 類型成員,但不會複製對象成員、引用對象 ArrayList<?> v = (ArrayList<?>) super.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(e); } }
返回 ArrayList 的 Object 數組
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
public E get(int index)
獲取指定位置上的元素,從0開始
public E get(int index) { rangeCheck(index);//檢查是否越界 return elementData(index); } // 檢查數組是否在界線內 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
public E set(int index, E element)
設置 index 位置元素的值
public E set(int index, E element) { rangeCheck(index);//越界檢查 E oldValue = elementData(index);//獲取舊數值 elementData[index] = element; return oldValue; }
public boolean add
增加指定的元素到ArrayList的指定位置,默認最後位置
public boolean add(E e) { // 確定ArrayList的容量大小---嚴謹 // 注意:size + 1,保證資源空間不被浪費, // ☆☆☆按當前情況,保證要存多少個元素,就只分配多少空間資源 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } //在這個ArrayList中的指定位置插入指定的元素 public void add(int index, E element) { rangeCheckForAdd(index);//判斷角標是否越界 //看上面的,size+1,保證資源空間不浪費,按當前情況,保證要存多少元素,就只分配多少空間資源 ensureCapacityInternal(size + 1); // Increments modCount!! //第一個是要複製的數組,第二個是從要複製的數組的第幾個開始, // 第三個是複製到那,四個是複製到的數組第幾個開始,最後一個是複製長度 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
public E remove
移除指定位置的元素 或者指定元素
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1;//要移動的長度 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); // 將最後一個元素置空 elementData[--size] = null; return oldValue; } //移除list中指定的第一個元素(符合條件索引最低的) 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; }
更多方法請移步ArrayList源碼分析