ArrayList源码
1.概覽
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable實現(xiàn)了 RandomAccess 接口,因此支持隨機訪問。這是理所當(dāng)然的,因為ArrayList 是基于數(shù)組實現(xiàn)的。
數(shù)組的默認(rèn)大小為 10。
private static final int DEFAULT_CAPACITY = 10;2.序列化
ArrayList基于數(shù)組實現(xiàn),并且具有動態(tài)擴容特性,因此保存元素的數(shù)組不一定都會被使用,那么就沒必要全部進行序列化。
保存元素的數(shù)組elementData使用transient修飾,該關(guān)鍵字聲明數(shù)組默認(rèn)不會被序列化。
transient Object[] elementData; // non-private to simplify nested class accessArrayList 實現(xiàn)了writeObject() 和 readObject() 來控制只序列化數(shù)組中有元素填充那部分內(nèi)容。
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {elementData = EMPTY_ELEMENTDATA;// Read in size, and any hidden stuffs.defaultReadObject();// Read in capacitys.readInt(); // ignoredif (size > 0) {// be like clone(), allocate array based upon size not capacityensureCapacityInternal(size);Object[] a = elementData;// Read in all elements in the proper order.for (int i=0; i<size; i++) {a[i] = s.readObject();}} } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject();// Write out size as capacity for behavioural compatibility with clone()s.writeInt(size);// Write out all elements in the proper order.for (int i=0; i<size; i++) {s.writeObject(elementData[i]);} if (modCount != expectedModCount) {throw new ConcurrentModificationException();} }序列化時需要使用 ObjectOutputStream 的 writeObject() 將對象轉(zhuǎn)換為字節(jié)流并輸出。
而 writeObject() 方法在傳入的對象存在 writeObject() 的時候會去反射調(diào)用該對象的 writeObject() 來實現(xiàn)序列化。
反序列化使用的是 ObjectInputStream 的readObject() 方法,原理類似。
ArrayList list = new ArrayList(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(list);3.擴容
添加元素時使用 ensureCapacityInternal() 方法來保證容量足夠,如果不夠時,需要使用 grow() 方法進行擴容,新容量的大小為 oldCapacity + (oldCapacity>> 1) ,也就是舊容量的 1.5 倍。
擴容操作需要調(diào)用 Arrays.copyOf() 把原數(shù)組整個復(fù)制到新數(shù)組中,這個操作代價很高,因此最好在創(chuàng)建 ArrayList 對象時就指定大概的容量大小,減少擴容操作的次數(shù)。
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true; } private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);} ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity); } private void grow(int minCapacity) {// overflow-conscious codeint 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); }4.刪除元素
需要調(diào)用 System.arraycopy() 將 index+1 后面的元素都復(fù)制到 index 位置上,該操作的時間復(fù)雜度為 O(N),可以看出 ArrayList 刪除元素的代價是非常高的。
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; // clear to let GC do its workreturn oldValue; }5. Fail-Fast
modCount 用來記錄 ArrayList 結(jié)構(gòu)發(fā)生變化的次數(shù)。
- 結(jié)構(gòu)發(fā)生變化是指添加或者刪除至少一個元素的所有操作,或者是調(diào)整內(nèi)部數(shù)組的大小,僅僅只是設(shè)置元素的值不算結(jié)構(gòu)發(fā)生變化。
在進行序列化或者迭代等操作時,需要比較操作前后 modCount 是否改變,如果改變了需要拋出 ConcurrentModificationException。
private void writeObject(java.io.ObjectOutputStream s)throws java.io.IOException{// Write out element count, and any hidden stuffint expectedModCount = modCount;s.defaultWriteObject();// Write out size as capacity for behavioural compatibilitywith clone()s.writeInt(size);// Write out all elements in the proper order.for (int i=0; i<size; i++) {s.writeObject(elementData[i]);} if (modCount != expectedModCount) {throw new ConcurrentModificationException();} }?
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的ArrayList源码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 容器(Collection/Map)、容
- 下一篇: CopyOnWriteArrayList