ArrayList的主要成員變量:
//數組默認初始容量
private static final int DEFAULT_CAPACITY = 10;
//定義一個空的數組實例以供其他需要用到空數組的地方調用
private static final Object[] EMPTY_ELEMENTDATA = {};
/*
定義一個空數組,跟前面的區別就是這個空數組是用來判斷ArrayList第一添加數據的時候要擴容多少。
默認的構造器情況下返回這個空數組
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/*
數據存的地方它的容量就是這個數組的長度,同時只要是使用默認構造器:
(DEFAULTCAPACITY_EMPTY_ELEMENTDATA )第一次添加數據的時候容量擴容爲DEFAULT_CAPACITY = 10
*/
transient Object[] elementData;
private int size;//當前數組的長度
部分源碼分析:
//序列號
private static final long serialVersionUID = 8683452581122892189L;
//默認容量
private static final int DEFAULT_CAPACITY = 10;
/**
* 一個空數組
* - 當用戶指定該 ArrayList 容量爲 0 時,返回該空數組
* - ArrayList(int initialCapacity)
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 一個空數組實例
* - 當用戶沒有指定 ArrayList 的容量時(即調用無參構造函數),返回的是該數組==>剛創建一個 ArrayList 時,其內數據量爲 0。
* - 當用戶第一次添加元素時,該數組將會擴容,變成默認容量爲 10(DEFAULT_CAPACITY) 的一個數組
* ===>通過 ensureCapacityInternal() 實現
* 它與 EMPTY_ELEMENTDATA 的區別就是:該數組是默認返回的,而後者是在用戶指定容量爲 0 時返回
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* ArrayList基於數組實現,用該數組保存數據, ArrayList 的容量就是該數組的長度
* - 該值爲 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 時,當第一次添加元素進入 ArrayList 中時,數組將擴容值 DEFAULT_CAPACITY(10)
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* ArrayList實際存儲的數據數量
*/
private int size;
/**
* 創建一個初試容量的、空的ArrayList
* - 可能報錯: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
* @param initialCapacity 初始容量
* @throws IllegalArgumentException 當初試容量值非法(小於0)時拋出
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 數組緩衝區爲 EMPTY_ELEMENTDATA,注意與 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的區別
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}
/**
* 無參構造函數:
* - 創建一個 空的 ArrayList,此時其內數組緩衝區 elementData = {}, 長度爲 0
* - 當元素第一次被加入時,擴容至默認容量 10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
擴容機制:
/**
* 添加新值到 list 末尾
* @param e 添加的值
* @return <tt>true</tt>
*/
public boolean add(E e) {
// 確定ArrayList的容量大小---嚴謹
// 注意:size + 1,保證資源空間不被浪費,按當前情況,保證要存多少個元素,就只分配多少空間資源
ensureCapacityInternal(size + 1); // 這裏是size是指已經有幾個元素,如果是初次add,size爲0
// 添加 e 到 ArrayList 中,然後 size 自增 1
elementData[size++] = e;
return true;
}
/**
* 指定 ArrayList 的容量
* @param minCapacity 指定的最小容量
*/
public void ensureCapacity(int minCapacity) {
// 最小擴充容量,默認是 10
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
// 若用戶指定的最小容量 > 最小擴充容量,則以用戶指定的爲準,否則還是 10
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
/**
* 私有方法:明確 ArrarList 的容量,提供給本類使用的方法
* - 用於內部優化,保證空間資源不被浪費:尤其在 add() 方法添加時起效
* @param minCapacity 指定的最小容量
*/
private void ensureCapacityInternal(int minCapacity) {
//第一次添加,調用add()時,elementData == {}
// 若 elementData == {},則取 minCapacity 爲 默認容量和參數 minCapacity 之間的最大值
//假設第一次添加,調用add(),minCapacity爲0,默認容量爲10,則取DEFAULT_CAPACITY默認容量的值,即爲10
// 注:ensureCapacity() 是提供給用戶使用的方法,在 ArrayList 的實現中並沒有使用
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
/**
* 私有方法:明確 ArrayList 的容量
* - 用於內部優化,保證空間資源不被浪費:尤其在 add() 方法添加時起效
* @param minCapacity 指定的最小容量
*/
private void ensureExplicitCapacity(int minCapacity) {
// 將“修改統計數”+1,該變量主要是用來實現fail-fast機制的
modCount++;
// 防止溢出代碼:確保指定的最小容量 > 數組緩衝區當前的長度
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 私有方法:擴容,以確保 ArrayList 至少能存儲 minCapacity 個元素
* - 擴容計算:newCapacity = oldCapacity + (oldCapacity >> 1);
* @param minCapacity 指定的最小容量
*/
private void grow(int minCapacity) {
// 防止溢出代碼
int oldCapacity = elementData.length;
// 運算符 >> 是帶符號右移. 如 oldCapacity = 10,則 newCapacity = 10 + (10 >> 1) = 10 + 5 = 15
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0) // 若 newCapacity 依舊小於 minCapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) // 若 newCapacity 大於最大存儲容量,則進行大容量分配
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}