ArrayList源碼閱讀筆記
內部屬性
//默認容量
private static final int DEFAULT_CAPACITY = 10;
//對於已知大小爲0 的 返回此空數組
private static final Object[] EMPTY_ELEMENTDATA = {};
//默認容量DEFAULT_CAPACITY的空數組 , 暫時實際爲0 的空數組 ,初次執行add方法時,會擴容爲DEFAULT_CAPACITY
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//存放數據的數組的緩存變量,不可序列化
transient Object[] elementData;
//元素數量
private int size;
//父級AbstractList的成員屬性:用於記錄集合結構變化次數(擴容、刪除、新增等所有會改變集合長度的操作)
protected transient int modCount = 0;
構造方法
1、public ArrayList(int initialCapacity) :
根據給定大小,初始化elementData ;
如果大小爲0 ,設置 elementData = EMPTY_ELEMENTDATA 空數組
2、public ArrayList() :
設置 elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA空數組,
初次執行add()時會被擴容爲默認大小
3、public ArrayList(Collection<? extends E> c) :
c不能爲null,c長度爲0 ,設置elementData = EMPTY_ELEMENTDATA 空數組 ,
否則elementData 長度爲c的大小
增刪改查
add : 新增
1、如果是指定索引新增:檢查索引 rangeCheckForAdd(int index)
2、判斷是否需要擴容 (當前集合元素個數+1,作爲最小參數)
3、添加元素
set : 修改
1、檢查索引 rangeCheck(index);
2、修改
remove: 刪除
1、根據索引刪除 : 檢查索引 rangeCheck(index);
2、刪除
get : 查看
1、檢查索引 rangeCheck(index);
2、返回元素
擴容機制
1、根據當前集合實際元素siez + 1 作爲集合需要的最小容量值,判斷是否需要擴容 【應爲只有add 纔會有擴容,所以需要用size+1判斷本次新增是否需要擴容】
2、 ensureCapacityInternal:確定內部需要容量最小值
private void ensureCapacityInternal(int minCapacity) {
//初次執行add 無參構造容量設置爲默認容量
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
3、:ensureExplicitCapacity-確保容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//所需最小容量 大於 當前elementData長度 執行擴容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
4、執行擴容:
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 擴容 1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0) //擴容1.5倍後,新容量 小於 所需最小容量 ,使用最小容量爲擴容後大小
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) //擴容1.5倍後,新容量超過數組支持的最大容量值,使用最大值
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);//拷貝數據到一個新的容量大小的數組中
}
遍歷
foreach 使用了modCount結構變化次數驗證,遍歷過程中改變size操作會報ConcurrentModificationException
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
Iterator:內部類Itr迭代器 remove方法顯示的設置modCount跟操作後相等,所以支持迭代過程中修改
private class Itr implements Iterator<E> {
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
序列化 序列化後的流中記錄了集合結構變化次數,所以讀操作後在修改,也會發現
讀 :readObject
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
寫 :writeObject
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int 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();
}
}