1. 程式人生 > >ArrayList 詳解

ArrayList 詳解

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不會報錯。