ArrayList 是 Java 最常用的動態陣列實現。本文基於 **JDK 1.8 (OpenJDK 8u40+)** 原始碼,深度解析其核心機制:擴容策略、快速失效迭代器、SubList 視圖、序列化與執行緒安全。
java.lang.Object
↓
java.util.AbstractCollection<E> (實作 toArray, contains, remove 等通用方法)
↓
java.util.AbstractList<E> (實作 List 介面骨架、迭代器、subList、modCount)
↓
java.util.ArrayList<E> (核心:Object[] elementData、動態擴容、隨機存取)
實作介面:`List
transient Object[] elementData; // 實際儲存陣列,transient 自定序列化
private int size; // 邏輯大小 (元素個數)
protected transient int modCount = 0; // 修改次數 (繼承自 AbstractList),用於快速失效
// 預設容量 10
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // 共享空陣列 {}
}
// 指定初始容量
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
// 從 Collection 建立
public ArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
elementData = EMPTY_ELEMENTDATA;
}
}
**延遲初始化**:預設建構子不立即分配陣列,第一次 `add` 時才分配容量 10 (見 `grow`)。
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5 倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
// MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 (保留給 VM header)
private class Itr implements Iterator {
int cursor; // 下一個要返回的索引
int lastRet = -1; // 最後返回的索引
int expectedModCount = modCount; // 快照
public boolean hasNext() { return cursor != size; }
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size) throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
**僅為檢測程式錯誤**,不保證多執行緒安全。並發環境請用 `Collections.synchronizedList`、`CopyOnWriteArrayList` 或 `java.util.concurrent` 容器。
public List subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
// 內部類 SubList (非 RandomAccess)
class SubList extends AbstractList {
private final AbstractList l; // 父列表引用
private final int offset; // 起始偏移
private int size; // 子列表大小
SubList(AbstractList list, int fromIndex, int toIndex) {
this.l = list;
this.offset = fromIndex;
this.size = toIndex - fromIndex;
this.modCount = l.modCount; // 共享 modCount
}
public E get(int index) {
rangeCheck(index);
return l.get(index + offset); // 委派給父列表
}
public E set(int index, E element) {
rangeCheck(index);
return l.set(index + offset, element);
}
// add/remove 同樣委派並同步修改 size、modCount
}
// RandomAccessSubList 僅多實作 RandomAccess 標記介面
class RandomAccessSubList extends SubList implements RandomAccess { ... }
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
int expectedModCount = modCount;
s.defaultWriteObject(); // 寫入 size, modCount 等非 transient 欄位
s.writeInt(size); // 寫入邏輯大小
for (int i = 0; i < size; i++) s.writeObject(elementData[i]); // 僅寫入有效元素
if (modCount != expectedModCount) throw new ConcurrentModificationException();
}
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
s.readInt(); // 讀取 size (已由 defaultReadObject 讀入,這行實際多餘但保留相容)
if (size < 0) throw new InvalidObjectException("Invalid size: " + size);
elementData = (size == 0) ? EMPTY_ELEMENTDATA : new Object[size];
for (int i = 0; i < size; i++) elementData[i] = s.readObject();
}
**自定序列化** 只儲存有效元素 (size),忽略陣列尾部空洞,節省空間並確保反序列化後 `elementData.length == size` (緊湊)。
| 容器 | 執行緒安全 | 適用場景 | 效能特徵 |
|---|---|---|---|
| ArrayList | 否 | 單執行緒、或外部同步 | 最快、隨機存取 O(1) |
| Collections.synchronizedList | 是 (粗粒度鎖) | 低併發、需遍歷時手動同步 | 鎖競爭大、遍歷需手動 synchronized |
| CopyOnWriteArrayList | 是 (寫時複製) | 讀多寫少、遍歷頻繁、需快照語意 | 寫入慢 (複製陣列)、記憶體雙倍、迭代器不支援 remove |
| Vector | 是 (同步方法) | 舊代碼相容,**不推薦新專案使用** | 同步開銷大、擴容策略 2倍 |