ArrayList 詳解

remove的核心處理 & add在擴容或其餘進行數組移動操做( eg. addAll、add(index, obj)), 時都涉及數組元素的複製移動System.arraycopy調用native方式。java

remove

從 index+1 至 end 的元素前移數組

add

在初始化時若沒指定容量則構建的是空數組,在第一次add時,擴容至DEFAULT_CAPACITY= 10.  this

默認下的擴容策略是: 原容量/2 (newCapacity = oldCapacity + (oldCapacity >> 1))spa

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);
    }

在擴容時,須要經過Arrays.copyOf來複制數組元素(實現也是System.arraycopy)3d

重要成員

  • Object[] elementData:經過內部維護數組來存儲數據。 在add時會斷定是否須要須要擴容(最大限制是Integer.MAX_VALUE)
  • int size: 實際維持的元素個數 數。 add時加一, remove時減一。
    與elementData.length不是一個意思。在writeObject方法中能佐證)
  • int modCount: 繼承自AbstractList, 用來肯定arrayList的結構變動(新增、擴容、刪除、排序、清空)次數, 只有++; 由迭代器(Iterator)和列表迭代器(ListIterator)使用,當進行next()、remove()、previous()、set()、add()等操做時,若是modCount的值意外改變,就會拋出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);
		
	}

初始化指定容量執行結果:
code

初始化不指定容量執行結果:
blog

ConcurrentModificationException

  • 只要實現了Iterator接口的類,均可以使用for-Each循環來遍歷!
  • 集合循環遍歷時所使用的迭代器Iterator有一個要求:在迭代的過程當中,除了使用迭代器(如:Iterator.remove()方法)對集合增刪元素外,是不容許直接對集合進行增刪操做。不然將會拋出 ConcurrentModificationException異常。因此,因爲集合的for-Each循環本質上使用的仍是Iterator來迭代,所以也要注意這個陷阱。

在for循環中直接remove時拋出異常
排序

普通的for循環方式刪除元素時是經過System.arraycopy調用native的方式進行數組邊界內的複製, size一直會在變化,結果沒法控制(沒法清空數據或下標越界異常)繼承

for-Each循環是經過擴展Iterable接口的iterator()方法返回在ArrayList內部對於Iterator接口的實現類Itr來進行處理。接口

類中一個重要元素expectedModCount初始值等於modCount。

在next()執行階段會調用checkForComodification() 來斷定modCount與expectedModCount是否一致, 不然拋出異常。
而在Iterator.remove方法會從新設置expectedModCount值, 因此當調用Iterator.next等方法時checkForComodification不會報錯。

相關文章
相關標籤/搜索