Java 集合框架是日常開發最核心的工具箱。本文系統梳理 Collection、Map 兩大體系,深度對比 HashSet/LinkedHashSet/TreeSet、ArrayList/LinkedList/Vector/Stack、HashMap/Hashtable/WeakHashMap 等核心實現類的資料結構、特性、效能與適用場景,並提供自製 HashMap 教學實作與選型決策表。
一、集合框架體系總覽
Collection
├─ List (有序、可重複)
│ ├─ ArrayList (動態陣列)
│ ├─ LinkedList (雙向鏈表)
│ ├─ Vector (同步動態陣列,legacy)
│ └─ Stack (繼承 Vector,LIFO)
└─ Set (無序、不可重複)
├─ HashSet (HashMap 底層)
├─ LinkedHashSet (LinkedHashMap 底層,插入序)
└─ TreeSet (TreeMap 底層,紅黑樹,有序)
Map (鍵值對、Key 不重複)
├─ HashMap (陣列+鏈表/紅黑樹)
├─ LinkedHashMap (雙向鏈表維護插入/存取序)
├─ Hashtable (同步,legacy,不允許 null)
├─ TreeMap (紅黑樹,Key 有序)
└─ WeakHashMap (弱引用 Key,適合快取)
二、Set 族群深度對比
1. HashSet
- 底層
HashMap,key=元素, value=PRESENT
- 無序、不重複、允許一個
null
- 判斷相等:
hashCode() 相同且 equals() 為 true
- 效能:增刪查 O(1) 平均
2. LinkedHashSet
- 底層
LinkedHashMap,雙向鏈表維護插入順序
- 迭代順序 = 插入順序
- 效能略低於 HashSet(維護鏈表開銷)
3. TreeSet / SortedSet
- 底層
TreeMap(紅黑樹),元素自然順序或自訂 Comparator排序
- 實作
NavigableSet:支援 floor/ceiling/higher/lower、subSet/headSet/tailSet 區間操作
- 效能:增刪查 O(log n)
- 可存
null(需 Comparator 處理)
程式碼範例:TreeSet 自訂排序
static class Person { int id; String name; int age; ... }
static class MyComparator implements Comparator<Person> {
public int compare(Person p1, Person p2) {
if (p1 == p2) return 0;
if (p1 == null) return -1;
if (p2 == null) return 1;
return Integer.compare(p1.id, p2.id);
}
}
TreeSet<Person> set = new TreeSet<>(new MyComparator());
set.add(new Person(3, "張三", 20));
set.add(new Person(1, "趙一", 18));
// 迭代輸出按 id 升序
三、List 族群深度對比
| 特性 | ArrayList | LinkedList | Vector | Stack |
| 底層結構 | 動態陣列 | 雙向鏈表 | 動態陣列 | 繼承 Vector |
| 隨機存取 | O(1) ✓ | O(n) ✗ | O(1) | O(n) |
| 頭尾增刪 | 尾 O(1) 頭 O(n) | O(1) ✓ | 尾 O(1) 頭 O(n) | 頭 O(1) |
| 中間增刪 | O(n) 移動元素 | O(n) 定位+O(1) | O(n) | O(n) |
| 執行緒安全 | 否 | 否 | 是(同步開銷大) | 是 |
| 擴容策略 | 1.5倍 | 無 | 2倍 | 2倍 |
| 適用場景 | 頻繁隨機讀、少增刪 | 頻繁增刪、佇列/棧 | 不推薦用 | LIFO 棧操作 |
Stack 經典操作
Stack<Person> stack = new Stack<>();
stack.push(p1); stack.push(p2);
Person top = stack.peek(); // 看頂不拿
Person popped = stack.pop(); // 彈出
int dist = stack.search(p1); // 距頂距離
四、Map 族群深度對比
1. HashMap 核心機制(詳見上篇深度解析)
- 陣列 + 鏈表/紅黑樹
- 允許一個
null key、多個 null value
- 非同步,高效能
- JDK 8 尾插法 + 樹化優化
2. Hashtable vs HashMap 關鍵差異
| 差異點 | Hashtable | HashMap |
| 父類 | Dictionary | AbstractMap |
| 同步 | 所有方法 synchronized | 非同步 |
| null 鍵/值 | 不允許 | 允許 1 null key + 多 null value |
| 遍歷方式 | Iterator + Enumeration | Iterator |
| 推薦度 | Legacy,不推薦 | 首選 |
同步替代方案:Collections.synchronizedMap(new HashMap<>()) 或 ConcurrentHashMap(JDK 8 高效能分段鎖/CAS)。
3. WeakHashMap:快取神器
Key 為弱引用(WeakReference),GC 時若無強引用自動回收條目
- 適用於「Key 生命週期不由 Map 控制」的快取場景
- 示例:
WeakHashMap<ClassLoader, Cache> 類載入器卸載時自動清理
五、自製 HashMap 教學實作
Entry 節點
static class Entry<K,V> {
final K key; V value; Entry<K,V> next;
Entry(K k, V v, Entry<K,V> n) { key=k; value=v; next=n; }
}
MyHashMap 核心
public class MyHashMap<K,V> {
private Entry[] table;
private static final int DEFAULT_CAPACITY = 16;
private int size;
public MyHashMap() { table = new Entry[DEFAULT_CAPACITY]; }
static int indexFor(int h, int length) { return h & (length - 1); }
public V get(Object key) {
if (key == null) return null;
int hash = key.hashCode();
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next)
if (e.hashCode() == hash && (e.key == key || key.equals(e.key)))
return e.value;
return null;
}
public V put(K key, V value) {
if (key == null) return null;
int hash = key.hashCode();
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next)
if (e.hashCode() == hash && (e.key == key || key.equals(e.key))) {
V old = e.value; e.value = value; return old;
}
table[i] = new Entry<>(key, value, table[i]); // 頭插法
return null;
}
}
六、選型決策速查表
| 需求 | 首選 | 備選 |
| 高效能 Key-Value,非同步 | HashMap | ConcurrentHashMap (多執行緒) |
| 保持插入順序 Map | LinkedHashMap | — |
| Key 自動排序/區間查詢 | TreeMap | — |
| 唯一元素集合,無序 | HashSet | — |
| 唯一元素,保持插入序 | LinkedHashSet | — |
| 唯一元素,需排序/區間 | TreeSet | — |
| 頻繁隨機存取列表 | ArrayList | — |
| 頻繁頭尾/中間增刪、佇列棧 | LinkedList / ArrayDeque | — |
| Key 生命週期外部管理的快取 | WeakHashMap | Caffeine/Guava Cache |
七、總結
Java 集合框架以 Collection/Map 為核心介面,針對不同資料結構(陣列、鏈表、紅黑樹、哈希表)提供豐富實現。掌握各類底層結構、時空複雜度、執行緒安全性、順序保證等核心特性,是寫出高效、正確、可維護程式碼的關鍵。實務中:優先 ArrayList/HashMap/HashSet,特定場景再選 LinkedList/TreeMap/LinkedHashSet/WeakHashMap/ConcurrentHashMap。
- 上一篇文章: Java 深度研究:HashMap 實現原理全解析 - 從拉鏈法到擴容重雜湊
- 下一篇文章: Java Lambda 表達式深度解析:變量捕獲、值捕獲語義與線程安全陷阱
Copyright ©
程式碼之家 All Rights Reserved