本文基於 JDK8java
ArrayList 底層經過動態數組的數據結構實現數組
ArrayList 的繼承與實現的關係圖以下所示。安全
如下說明摘自 JDK 文檔。數據結構
Iterable 接口:提供迭代器訪問能力,實現此接口容許對象經過 for-each 循環語句進行遍歷。併發
Collection 接口:集合層次結構中的根接口。集合中的一組對象稱爲元素。一些集合容許重複的元素,而另外一些則不容許。有些是有序的,而另外一些是無序的。 JDK 不提供此接口的任何直接實現,它提供了更多特定子接口的實現,例如 Set 和 List 。該接口一般用於傳遞集合並在須要最大通用性的地方使用。dom
AbstractCollection 抽象類:此類提供了 Collection 接口的基本實現,以最大程度地減小實現此接口所需的工做。ide
List 接口:Collection 接口的子接口,有序集合(也稱爲序列)。用戶經過該接口能夠精確控制列表中每一個元素的插入位置。用戶能夠經過其整數索引(集合中的位置)訪問元素,並在中搜索元素。函數
Serializable 接口:該標記接口提供類序列化或反序列化的能力。源碼分析
/** * 序列號 */ private static final long serialVersionUID = 8683452581122892189L; /** * 默認容量爲 10,經過 new ArrayList() 建立 */ private static final int DEFAULT_CAPACITY = 10; /** * 空數組,傳入容量爲 0 時使用,經過 new ArrayList(0) 建立 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 空數組,與 EMPTY_ELEMENTDATA 區分開來,經過 new ArrayList() 建立 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 存儲元素的數組 * transient 修飾此對象表示不序列化該屬性,由於 ArrayList 具備動態擴容的特性,數組中的元素會有剩餘 * 經過 writeObject 和 readObject 方法實現序列化和反序列化 */ transient Object[] elementData; // non-private to simplify nested class access /** * 數組的實際長度 */ private int size; /** * 能夠分配的最大容量 * Integer.MAX_VALUE - 8 是由於數組中有虛擬機保留的一些數據 * 強制分配可能會致使 OutOfMemoryError */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
無參構造器,經過 new ArrayList() 調用。性能
/** * 無參構造器,經過 new ArrayList() 調用 * 懶初始化,在添加第一個元素時將 elementData 擴容爲 DEFAULT_CAPACITY,減小內存的開銷 */ public ArrayList() { // 將 elementData 初始化爲 DEFAULTCAPACITY_EMPTY_ELEMENTDATA this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
構造一個具備指定初始容量的集合。
/** * 構造一個具備指定初始容量的集合 * @param initialCapacity 初始容量 * @throws IllegalArgumentException 初始容量爲負時拋出異常 */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // 初始化容量大於 0 的話,構造一個容量爲 initialCapacity 的數組 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // 初始化容量等於 0 的話,初始化爲空數組 EMPTY_ELEMENTDATA this.elementData = EMPTY_ELEMENTDATA; } else { // 初始化容量小於 0 的話就拋出異常 throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); } }
構造一個包含指定集合元素的集合。
/** * 構造一個包含指定集合元素的集合 * @param c 將其元素放入此列表的集合 * @throws NullPointerException 集合爲空時拋出 */ public ArrayList(Collection<? extends E> c) { // 將集合轉爲 Object[] 類型數組 elementData = c.toArray(); // 將 elementData.length 賦值給 size 並判斷是否爲 0 if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) // 由於當子類重寫父類時,能夠修改返回值類型,致使返回的類型可能不爲 Object[] if (elementData.getClass() != Object[].class) // 利用 Arrays 的 copyOf 函數複製成 Object[] 類型的 elementData elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 傳入集合長度爲 0 的話,初始化爲空數組 EMPTY_ELEMENTDATA this.elementData = EMPTY_ELEMENTDATA; } }
添加特定的元素到集合末尾。
/** * 添添加特定的元素到集合末尾 * @param e 添加到集合的元素 * @return 返回是否插入成功 */ public boolean add(E e) { // 檢查插入一個元素是否須要擴容 ensureCapacityInternal(size + 1); // 將元素插入到最後一位 elementData[size++] = e; return true; } /** * 確保傳入的最小內部容量 * @param minCapacity 最小容量 */ private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } /** * 計算所須要的最小容量 * @param elementData 原始數組 * @param minCapacity 所須要的最小容量 * @return 擴容後的大小 */ private static int calculateCapacity(Object[] elementData, int minCapacity) { // 若 elementData 爲 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,也就是經過 new ArrayList() 初始化的 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 此時 minCapacity 應該爲 1,返回初始化的默認容量 10 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } /** * 確保明確的須要擴容 * @param minCapacity 所須要的最小容量 */ private void ensureExplicitCapacity(int minCapacity) { // 修改次數 +1,用於 fail-fast 機制 modCount++; // 防止代碼溢出,當所須要的最小容量大於 elementData 的長度時才進行擴容 if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * 增長容量以確保它至少能夠保存最小容量參數指定數量的元素。 * @param minCapacity 所須要的最小容量 */ private void grow(int minCapacity) { // 舊容量大小 int oldCapacity = elementData.length; // 新容量 = 舊容量 + 舊容量*0.5,也就是舊容量的 1.5 倍大小 int newCapacity = oldCapacity + (oldCapacity >> 1); // 若是新容量小於所需的要最小容量,則將所需的容量賦值給新容量 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // 若是新容量的大小大於所能分配的最大容量,則新容量的大小根據所須要的最小容量從新計算 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: // 擴容完畢,win!將新容量複製給 elementData elementData = Arrays.copyOf(elementData, newCapacity); } /** * 由於根據舊容量*1.5分配容量超出最大容量,因此該函數用於計算最大容量分配 * @param minCapacity * @return */ private static int hugeCapacity(int minCapacity) { // 所須要最小容量小於 0 拋出 OutOfMemoryError if (minCapacity < 0) throw new OutOfMemoryError(); // 當所需容量大於 MAX_ARRAY_SIZE 時返回 Integer.MAX_VALUE 不然返回 MAX_ARRAY_SIZE return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
將指定的元素插入集合中指定位置。將當前在該位置的元素(若是有的話)和全部後續元素向右移動。
/** * 將指定的元素插入集合中指定位置 * 將當前在該位置的元素(若是有的話)和任何後續元素向右移動 * @param index 插入元素的位置 * @param element 插入的元素 * @throws IndexOutOfBoundsException 數組越界異常 */ public void add(int index, E element) { // 檢查該數組下標是否越界 rangeCheckForAdd(index); // 檢查插入一個元素是否須要擴容 ensureCapacityInternal(size + 1); // 將 elementData 中 index 位置開始的元素 // 複製到 elementData 中 index + 1 開始的位置,複製長度爲 size-index System.arraycopy(elementData, index, elementData, index + 1, size - index); // 將該元素添加到指定下標位置 elementData[index] = element; // 數組實際長度 +1 size++; } /** * 檢查添加時數組下標是否越界 * add 和 addAll 使用的 rangeCheck 版本。 */ private void rangeCheckForAdd(int index) { // 下標大於數組實際長度或小於 0 時拋出 IndexOutOfBoundsException if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * 構造 IndexOutOfBoundsException 的詳細異常信息 */ private String outOfBoundsMsg(int index) { // 返回越界的下標大小和實際數組長度 return "Index: "+index+", Size: "+size; }
將指定集合中的全部元素追加到集合的末尾。
/** * 將指定集合中的全部元素追加到集合的末尾 * * @param c 包含要添加到該集合的元素集合 * @return 集合是否插入成功 * @throws NullPointerException 指定集合爲空時拋出 */ public boolean addAll(Collection<? extends E> c) { // 將集合 c 轉爲 Object[] 類型數組 Object[] a = c.toArray(); // 插入的集合的長度 int numNew = a.length; // 檢查容量爲 size + numNew 時的擴容 ensureCapacityInternal(size + numNew); // 將集合 a 中的全部元素拷貝到 elementData 的最後 System.arraycopy(a, 0, elementData, size, numNew); // 增長數組的實際長度 size += numNew; // 若是插入的集合不爲空就返回 true,不然返回 false return numNew != 0; }
從指定位置開始,將指定集合中的全部元素插入此集合。將當前位於該位置的元素(若是有)和全部後續元素右移。
/** * 從指定位置開始,將指定集合中的全部元素插入此集合 * 將當前位於該位置的元素(若是有)和全部後續元素右移) * * @param index 插入集合的指定索引位置 * @param c 插入的指定集合 * @return 集合是否插入成功 * @throws IndexOutOfBoundsException 插入的下標是否越界 * @throws NullPointerException 集合爲空拋出異常 */ public boolean addAll(int index, Collection<? extends E> c) { // 檢查插入的指定下標是否越界 rangeCheckForAdd(index); // 將集合 c 轉爲 Object[] 類型數組 Object[] a = c.toArray(); // 集合 c 的長度 int numNew = a.length; // 檢查容量爲 size + numNew 時的擴容 ensureCapacityInternal(size + numNew); // 指定位置後數組要移動的長度 int numMoved = size - index; if (numMoved > 0) // 將 elementData 中 index 開始的元素複製到 elementData 中 index+numNew 的位置,複製長度爲 numMoved System.arraycopy(elementData, index, elementData, index + numNew, numMoved); // 將添加的數組 a 的數據複製到 elementData 中 index 開始的位置,複製長度爲 numNew System.arraycopy(a, 0, elementData, index, numNew); // 增長數組的實際長度 size += numNew; // 若是插入的集合不爲空就返回 true,不然返回 false return numNew != 0; }
刪除集合中指定位置的元素,將全部後續元素向左移動。
/** * 刪除集合中指定位置的元素,將全部後續元素向左移動。 * * @param index 刪除的指定下標 * @return 返回刪除的元素 * @throws IndexOutOfBoundsException 刪除的下標越界時拋出 */ public E remove(int index) { // 檢查下標是否越界 rangeCheck(index); // 修改次數 +1 modCount++; // 取出對應下標中要刪除的元素 E oldValue = elementData(index); // 刪除該下標中的元素,後面元素須要移動的長度 int numMoved = size - index - 1; if (numMoved > 0) // 若是 numMoved>0,也就是 index 不爲最後一位 // 將 elementData 中 index+1 位置開始的元素複製到 index 開始的位置,複製長度爲 numMoved System.arraycopy(elementData, index+1, elementData, index, numMoved); // 將最後一個元素置爲 null,方便 GC 回收,刪除的時候並無縮小容量 elementData[--size] = null; // 返回刪除的元素 return oldValue; } /** * 檢查給定的索引是否在範圍內。若是不是,則拋出 IndexOutOfBoundsException * 此方法不檢查索引是否爲負數,若是索引爲負數,則拋出 ArrayIndexOutOfBoundsException */ private void rangeCheck(int index) { // 當該下標大於等於數組實際長度時拋出異常 if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
從集合刪除第一次出現的指定元素,若是存在,則將其刪除。若是集合不包含元素,則集合保持不變。
/** * 從集合刪除第一次出現的指定元素,若是存在,則將其刪除。若是集合不包含元素,則集合保持不變。 * @param o 須要刪除的元素 * @return 返回是否刪除成功 */ public boolean remove(Object o) { // 若是要刪除的元素爲 null if (o == null) { // null 特殊處理,用 == 做比較 // 遍歷全部 elementData,找到第一個值爲 null 的,快速刪除對應的下標,返回 true for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { // 遍歷全部 elementData,使用 equals 比較兩個對象,找出第一次相等位置的下標快速刪除,返回 true for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } // 沒有對應的元素返回 false return false; } /** * 私有remove 方法,跳過邊界檢查而且不返回刪除的值。 * 與 remove(int index) 相比,缺乏越界檢查和返回值 */ private void fastRemove(int index) { // 減小越界檢查,提升性能 // 修改次數 +1 modCount++; // 刪除該下標中的元素,後面元素須要移動的長度 int numMoved = size - index - 1; if (numMoved > 0) // 若是 numMoved>0,也就是 index 不爲最後一位 // 將 elementData 中 index+1 位置開始的元素複製到 index 開始的位置,複製長度爲 numMoved System.arraycopy(elementData, index+1, elementData, index, numMoved); // 將最後一個元素置爲 null,方便 GC 回收,刪除的時候並無縮小容量 elementData[--size] = null; // 無返回值 }
從集合中刪除指定的集合中包含的全部元素。
/** * 從集合中刪除指定的集合中包含的全部元素 * @param c 刪除的集合 * @return 返回是否刪除 * @throws ClassCastException 若是該集合的元素的類與指定的集合不兼容拋出 * @throws NullPointerException 若是此列表包含 null 元素,而且指定的集合不容許使用null元素拋出 */ public boolean removeAll(Collection<?> c) { // 集合 c 不爲空,有空的話拋出 NullPointerException Objects.requireNonNull(c); // 批量刪除包含集合 c 的元素 return batchRemove(c, false); } /** * 批量刪除集合 * @param c 刪除的集合 * @param complement 刪除的方式 * complement == true 表示刪除不包含在集合 c 中的元素,求兩個集合的交集 * complement == false 表示刪除包含在集合 c 中的元素,求兩個集合的差集 * @return */ private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; // r 爲寫指針 w 爲讀指針 int r = 0, w = 0; // 是否修改的標誌 boolean modified = false; try { for (; r < size; r++) // 當 c 中不包含 elementData[r] 且 complement == false 時,elementData[w++] 存放的保留元素就是 elementData 中除去集合 c 有的元素 // 當 c 中包含 elementData[r] 且 complement == true 時,elementData[w++] 存放的是保留元素就是 elementData 和 集合 c 的交集 // 無論哪一種方式,存放的都是對應保留的元素 if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // 正常循環結束 r == size,不然 c.contains() 拋出了異常 if (r != size) { // 將 elementData 中 r 位置開始的元素複製到 elementData 中 w 開始的位置,複製長度爲 size-r // 也就是將出錯位置 r 開始全部元素移動到已經保留的元素 w 位置以後 System.arraycopy(elementData, r, elementData, w, size - r); // 更新保留的元素個數 w += size - r; } // 若是 w == size,表示所有元素保留,沒有修改,返回 false if (w != size) { // 將未保留的元素置爲 null,方便 GC 回收 for (int i = w; i < size; i++) elementData[i] = null; // 修改的次數 +未保留的元素個數 modCount += size - w; // 將保留的元素個數更新爲數組實際長度 size = w; // 標記修改爲功 modified = true; } } // 修改失敗返回 false return modified; }
僅保留此集合中指定集合中包含的元素。換句話說,從集合中刪除全部不包含在指定集合中的元素。
/** * 僅保留此集合中指定集合中包含的元素。換句話說,從集合中刪除全部不包含在指定集合中的元素。 * @param c 須要保留的指定集合 * @return 返回是否刪除 * @throws ClassCastException 若是該集合的元素的類與指定的集合不兼容拋出 * @throws NullPointerException 若是此列表包含 null 元素,而且指定的集合不容許使用null元素拋出 */ public boolean retainAll(Collection<?> c) { // 集合 c 不爲空,有空的話拋出 NullPointerException Objects.requireNonNull(c); // 批量刪除包含集合 c 的元素,和 removeAll 函數的區別就是 complement 參數 return batchRemove(c, true); }
返回集合中指定位置的元素。
/** * 返回集合中指定位置的元素 * @param index 須要返回元素的下標 * @return 返回指定位置的元素 * @throws IndexOutOfBoundsException 下標越界時拋出 */ public E get(int index) { // 檢查下標是否越界 rangeCheck(index); // 返回對應索引的元素 return elementData(index); } /** * 返回對應位置的元素 */ @SuppressWarnings("unchecked") E elementData(int index) { // 取出對應位置的元素並強轉 return (E) ele\mentData[index]; }
用指定的元素替換集合中指定位置的元素。
/** * 用指定的元素替換集合中指定位置的元素 * @param 替換的位置 * @param element 替換成的元素 * @return 返回被替換前的元素 * @throws IndexOutOfBoundsException 索引下標越界拋出 */ public E set(int index, E element) { // 檢查下標是否越界 rangeCheck(index); // 取出對應下標的元素 E oldValue = elementData(index); // 更新指定位置的元素 elementData[index] = element; // 返回更新前的值 return oldValue; }
將該集合的容量調整爲實際的大小,可使用此操做來最大程度地減小元素的存儲。
/** * 將該集合 elementData 的容量調整爲實際的大小,可使用此操做來最大程度地減小元素的存儲。 */ public void trimToSize() { // 修改次數 +1 modCount++; // 若是集合實際長度小於 elementData 的長度 if (size < elementData.length) { // 若是實際長度爲 0,elementData 初始化爲 EMPTY_ELEMENTDATA,不然將 elementData 從新複製爲一個長度爲 size 的數組 elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
實現 ArrayList 實例的序列化。
/** * 將 ArrayList 實例的狀態保存到流中(即對其進行序列化)。 * @serialData 寫出支持 ArrayList 實例的數組的長度(int),而後以正確的順序寫出全部元素(Object)。 */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{ // 定義 expectedModCount 記錄寫出前的 modCount, 防止在序列化期間元素被修改 int expectedModCount = modCount; // 默認的序列化方法(寫入非 transient 和非 static 修飾的屬性,size 屬性會被寫入) s.defaultWriteObject(); // 寫出大小 size s.writeInt(size); // 按正確的順序寫出全部元素 for (int i=0; i<size; i++) { s.writeObject(elementData[i]); } // 若是在此期間元素個數發生了變化,拋出 ConcurrentModificationException if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } }
從反序列化中重構 ArrayList 實例。
/** * 從流中重構 ArrayList 實例(即反序列化)。 */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // 初始化空數組 elementData = EMPTY_ELEMENTDATA; // 默認的反序列化方法(讀入非 transient 和非 static 修飾屬性,size 屬性會被讀入) s.defaultReadObject(); // 讀入集合的長度,能夠忽略,只是爲了和寫出對應 s.readInt(); if (size > 0) { // 計算所須要的最小容量 int capacity = calculateCapacity(elementData, size); // 檢查集合的容量和類型 SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity); // 根據 size 的大小進行擴容檢查 ensureCapacityInternal(size); // 定義空數組 Object[] a = elementData; // 按順序讀取元素存入數組 for (int i=0; i<size; i++) { a[i] = s.readObject(); } } }
刪除集合中全部元素。
/** * 刪除集合中全部元素 */ public void clear() { // 修改次數 +1 modCount++; // 給每一個元素賦爲 null,以便讓 GC 回收 for (int i = 0; i < size; i++) elementData[i] = null; // 數組實際長度置爲 0 size = 0; }
以正確的順序(從第一個元素到最後一個元素)返回一個包含此集合中全部元素的數組。
/** * 以正確的順序(從第一個元素到最後一個元素)返回一個包含此集合中全部元素的數組。 * 此方法充當基於數組的 API 和基於集合的 API 之間的橋樑。 * @return 返回以適當順序包含此列表中全部元素的數組 */ public Object[] toArray() { // 將集合複製爲數組 return Arrays.copyOf(elementData, size); }
判斷集合是否包含指定元素。
/* * 判斷集合是否包含指定元素。 */ public boolean contains(Object o) { // 經過調用 indexOf 方法返回的下標來判斷是否存在該元素 return indexOf(o) >= 0; } /** * 返回指定元素在集合中首次出現的索引,若是集合不包含該元素,則返回-1 */ public int indexOf(Object o) { // 若是指定元素爲 null if (o == null) { // 從頭遍歷全部元素,null 用 == 判斷,返回第一次 null 出現的下標 for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { // 從頭遍歷全部元素,使用 equals 判斷,返回第一次該元素出現的下標 for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } // 不存在該元素則返回 -1 return -1; }
返回指定元素在集合中最後一次出現的索引,若是集合不包含該元素,則返回 -1。
/** * 返回指定元素在集合中最後一次出現的索引,若是集合不包含該元素,則返回-1 */ public int lastIndexOf(Object o) { // 若是指定元素爲 null if (o == null) { // 從後往前遍歷全部元素,null 用 == 判斷,返回第一次 null 出現的下標,也就是最後一次出現 for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { // 從後往前遍歷全部元素,使用 equals 判斷,返回第一次該元素出現的下標,也就是最後一次出現 for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } // 不存在該元素則返回 -1 return -1; }
返回集合中的元素的個數。
/** * 返回集合中的元素的個數 */ public int size() { // 直接返回 size return size; }
判斷集合是否爲空。
/** * 判斷集合是否爲空 */ public boolean isEmpty() { // 經過判斷集合實際長度是否爲 0 return size == 0; }
返回集合中指定的 [fromIndex, toIndex) 位置之間的集合。 若是 fromIndex == toIndex,則返回集合爲空。
/** * 返回集合中指定 [fromIndex, toIndex) 位置元素構成的集合 * 若是 fromIndex == toIndex,返回空集合 */ public List<E> subList(int fromIndex, int toIndex) { // 檢測子集的下標是否越界 subListRangeCheck(fromIndex, toIndex, size); // 經過構造 SubList 返回,SubList 和 ArrayList 引用是同一個對象 return new SubList(this, 0, fromIndex, toIndex); } /* * 檢測子集的下標是否越界 */ static void subListRangeCheck(int fromIndex, int toIndex, int size) { // 檢測 fromIndex 是否小於 0 if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); // 檢測 toIndex 是否大於 size if (toIndex > size) throw new IndexOutOfBoundsException("toIndex = " + toIndex); // 檢測 fromIndex 是否大於 toIndex if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); }
從集合中的指定位置開始,以適當的順序返回此集合中元素的 list 迭代器。 指定的索引表示首次調用 ListIterator 的 next 將返回的第一個元素。 首次調用 ListIterator 的 previous 將返回具備指定索引減一的元素。ListIterator 迭代器爲 List 特有的迭代器。
/** * 從集合中的指定位置開始,以適當的順序返回此集合中元素的 list 迭代器。 * 返回的 list 迭代器爲 fast-fail * @throws IndexOutOfBoundsException */ public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); // 構建一個從指定索引位置的迭代器 return new ListItr(index); }
以正確的順序返回此集合中的全部元素的 list 迭代器。
/** * 返回此集合中的全部元素的 list 迭代器 * 返回的 list 迭代器爲 fast-fail */ public ListIterator<E> listIterator() { // 構建一個從頭開始的 list 迭代器 return new ListItr(0); }
以正確的順序返回此集合中的全部元素的迭代器。
/** * 以正確的順序返回此集合中的全部元素的迭代器 * 返回的迭代器爲 fast-fail */ public Iterator<E> iterator() { return new Itr(); }
Itr 類實現了 Iterator 接口,具備迭代器的基本方法。
private class Itr implements Iterator<E> { /** * 下一個要返回的元素的索引 */ int cursor; /** * 返回最後一個元素的索引,沒有則返回 -1 */ int lastRet = -1; /** * 構建迭代器對象時記錄 modCount */ int expectedModCount = modCount; Itr() {} /** * 判斷是否有下一個元素 */ public boolean hasNext() { return cursor != size; } /** * 獲取下一個元素 */ @SuppressWarnings("unchecked") public E next() { checkForComodification(); /* 省略 */ } @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { /* 省略 */ checkForComodification(); } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; // 將刪除後的 modCount 賦給 expectedModCount expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } /** * 檢測 ArrayList 中的 modCount 和當前迭代器對象的 expectedModCount 是否一致 */ final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
ListItr 類繼承 Itr 類,實現 ListIterator 接口,在迭代器的基本方法上,擴充了 List 特有的迭代器方法。
private class ListItr extends Itr implements ListIterator<E> { /** * 初始化 ListItr */ ListItr(int index) { super(); cursor = index; } /** * 判斷是否有上一個元素 */ public boolean hasPrevious() { return cursor != 0; } /** * 返回下一個元素的下標 */ public int nextIndex() { return cursor; } /** * 返回上一個元素的下標 */ public int previousIndex() { return cursor - 1; } /** * 返回上一個元素 */ @SuppressWarnings("unchecked") public E previous() { checkForComodification(); /* 省略 */ } /** * 修改元素 */ public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); /* 省略 */ } /** * 添加元素 */ public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; // 將添加後的 modCount 賦給 expectedModCount expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
fail-fast 快速失敗機制是集合類應對併發訪問在對集合進行迭代過程當中,內部對象結構發生變化的一種防禦措施。
ArrayList 類的 iterator() 和 listIterator() 方法返回的迭代器都是 fail-fast 的。 若是列表在建立迭代器以後的任什麼時候間進行結構上的修改,除非經過迭代器本身的 remove() 或 add(Object) 方法,不然迭代器將拋出 ConcurrentModificationException。所以,面對併發修改,迭代器會迅速而乾淨地失敗,而不是在未來的不肯定時間內冒着不肯定行爲的風險。
在迭代過程執行 Iterator 的 remove 或 next 方法時,會經過 checkForComodification 方法來判斷 modCount 是否發生了變化,若是在迭代過程當中執行了 ArrayList 方法的 remove 或 add 等方法會形成 modeCount 改變,此時經過 checkForComodification 方法判斷髮現 expectedModCount != modCount,則拋出 ConcurrentModificationException。所以在迭代過程當中進行刪除操做時,須要調用 Iterator 的 remove 方法,另外 foreach 循環本質上也是迭代器實現的。