Java 集合框架中 List 介面的三大主力實現——ArrayList、LinkedList、Vector,雖然都實現有序、可重複的元素集合,但底層資料結構、執行緒安全性、效能特徵截然不同。本文從原始碼、複雜度、擴容機制、適用場景四個維度全方位對比。
| 維度 | ArrayList | LinkedList | Vector |
|---|---|---|---|
| 底層結構 | 動態陣列 (Object[]) | 雙向鏈表 (Node<E>) | 動態陣列 (Object[]) |
| 執行緒安全 | 非同步 (非安全) | 非同步 (非安全) | 同步 (安全,方法級 synchronized) |
| 隨機存取 | O(1) 極快 | O(n) 需遍歷 | O(1) |
| 頭尾插入/刪除 | O(n) 需搬移 | O(1) 僅改指標 | O(n) |
| 中間插入/刪除 | O(n) 搬移元素 | O(n) 定位 + O(1) 改指標 | O(n) |
| 記憶體開銷 | 低 (連續記憶體) | 高 (每節點 3 引用) | 低 |
| 擴容策略 | 1.5 倍 (newCapacity = old + old>>1) | 無擴容概念 | 2 倍 (預設),可指定 capacityIncrement |
| 實現介面 | List, RandomAccess, Cloneable, Serializable | List, Deque, Cloneable, Serializable | List, RandomAccess, Cloneable, Serializable |
transient Object[] elementData:transient 避免序列化空槽位,writeObject 手動序列化實際大小。add() → ensureCapacityInternal() → grow() → Arrays.copyOf()。modCount 記錄結構性修改次數,迭代器遍歷時檢測並發修改拋 ConcurrentModificationException。Collections.binarySearch() 等演算法選擇索引而非迭代器二分查找。Node<E> { E item; Node<E> next, prev; } 組成雙向鏈表。first/last 指標與 size 計數器。Deque 介面,原生支援 push/pop/peek (Stack)、offer/poll/peek (Queue) 操作。node(index) 判斷 index < (size >> 1) 從頭/尾雙向遍歷,縮減一半步數。synchronized,鎖粒度粗,效能差。ConcurrentModificationException。Stack<E> extends Vector<E> 違反組合優於繼承原則,官方建議用 Deque (如 ArrayDeque) 替代。| 操作 | ArrayList | LinkedList | Vector |
|---|---|---|---|
| 尾部新增 100 萬 | ~15 ms | ~25 ms | ~45 ms |
| 頭部新增 10 萬 | ~1200 ms | ~3 ms | ~1300 ms |
| 隨機存取 100 萬次 | ~2 ms | ~1800 ms | ~3 ms |
| 中間插入 10 萬 | ~800 ms | ~900 ms (含定位) | ~850 ms |
| 記憶體佔用 | ~4 MB | ~24 MB | ~4 MB |
需要執行緒安全?
├── 是 → 考慮 Collections.synchronizedList(new ArrayList<>())
│ 或 CopyOnWriteArrayList (讀多寫少)
│ 或並發包 ConcurrentLinkedDeque
└── 否 → 主要操作是什麼?
├── 隨機存取/尾部新增/遍歷 → ArrayList (首選)
├── 頻繁頭尾增刪/佇列棧操作 → LinkedList / ArrayDeque
├── 固定大小/極致效能 → 基本陣列 T[] / VarHandle
└── 不確定 → ArrayList (通用性最強)
new ArrayList<>(estimatedSize) 避免多次擴容複製。List<String> list = new ArrayList<>();,便於後續替換實現。ArrayList + 外部同步或並發集合。CopyOnWriteArrayList 適合「讀多寫少、遍歷時不允許鎖住」場景;寫入頻繁請用鎖分離或並發佇列。Serializable,但 LinkedList 節點較多序列化較慢。ArrayList 是 90% 場景的最佳預設選擇;LinkedList 僅在雙端佇列/棧語義或極端頭尾操作場景發光發熱;Vector 與 Stack 為歷史遺留,**新項目嚴禁使用**。理解底層資料結構與複雜度,才能在架構設計與效能調優中做出正確抉擇。