ArrayList 詳解
阿新 • • 發佈:2019-05-02
remove
刪除操作涉及陣列元素的複製移動!!
比較重要的幾個元素
- Object[] elementData:通過內部維護陣列來儲存資料。 在add時會判定是否需要需要擴容(最大限制是Integer.MAX_VALUE)。 在初始化時若沒指定容量,則構建的是空陣列,在第一次add時,擴容至DEFAULT_CAPACITY= 10,需要通過Arrays.copyOf來複制陣列元素!!
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; 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: elementData = Arrays.copyOf(elementData, newCapacity); }
- int size: 實際維持的元素個數 (與elementData.length不是一個意思)數。 add時加一, remove時減一。
在writeObject方法中能佐證與elementData.length不是一個意思
- int modCount: 繼承自AbstractList, 用來確定arrayList的結構變更次數, 只有++; 由迭代器(Iterator)和列表迭代器(ListIterator)使用,當進行next()、remove()、previous()、set()、add()等操作時,如果madCount的值意外改變,就會丟擲ConcurrentModificationException異常。
public static void main(String[] args) throws Exception { ArrayList<String> list = new ArrayList<String>(1); Field file = ArrayList.class.getDeclaredField("elementData"); file.setAccessible(true); Object[] object = (Object[]) file.get(list); System.out.println("初始size: " + list.size()); System.out.println("初始陣列容量:" + object.length); list.add("1"); Object[] object1 = (Object[]) file.get(list); System.out.println("新增第1個元素後的size:" + list.size()); System.out.println("新增第1個元素後的陣列容量:" + object1.length); }
初始化指定容量執行結果:
初始化不指定容量執行結果:
ConcurrentModificationException
普通的for迴圈方式刪除元素時, size()一直在變化,導致無法清空資料。而加強for迴圈則利用了迭代器進行遍歷,遍歷時發生了異常並丟擲。
在ArrayList內部對於Iterator介面的實現類Itr(ListItr)有一個重要元素expectedModCount初始值等於modCount。在Iterator.remove方法會重新設定expectedModCount值, 所以 當呼叫Iterator.next等方法時checkForComodification不會報錯。