Map 與 Set 是 Java 集合框架兩大支柱。本文聚焦 HashMap、Hashtable、HashSet 三者的繼承體系、線程安全、空值策略、遍歷方式、哈希計算、擴容機制七大核心差異。
| 維度 | Hashtable | HashMap | HashSet |
|---|---|---|---|
| 繼承父類 | Dictionary | AbstractMap | AbstractSet (內部用 HashMap) |
| 實現介面 | Map | Map | Set |
| 線程安全 | 同步(方法級 synchronized) | 非同步 | 非同步 |
| 允許 null | Key/Value 皆不允許 | 1 個 null Key,多個 null Value | 1 個 null 元素 |
| contains 方法 | contains / containsKey / containsValue | containsKey / containsValue(無 contains) | contains |
| 遍歷方式 | Iterator + Enumeration(歷史包袱) | Iterator | Iterator |
| 哈希值計算 | 直接用 key.hashCode() | 扰動函數重新計算(高位混合低位) | 同 HashMap |
| 初始容量/擴容 | 11,old*2+1 | 16(2^n),2倍擴容 | 同 HashMap |
Map<String, String> map = new HashMap<>();
map.put("key", null);
map.get("key"); // 回傳 null
map.get("nonexistent"); // 也回傳 null
// 無法區分「值為 null」vs「Key 不存在」
map.containsKey("key"); // 必須用此判斷
// JDK 1.8 靜態擾動函數
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
// 將高 16 位與低 16 位異或,減少碰撞,提升分佈均勻度
Hashtable 直接使用 hashCode(),高位資訊浪費,碰撞率較高。
newCapacity = oldCapacity * 2 + 1(保持奇數,略減碰撞)newCapacity = oldCapacity << 1(保持 2 的冪次,配合 (n - 1) & hash 位運算取模,極快)HashSet 內部持有一個 HashMap<E, Object>,所有元素作為 Key 存入,Value 統一為 PRESENT = new Object()。因此特性與 HashMap 高度一致。
Key 為弱引用,GC 時自動清理無強引用的 Key,適合元數據快取。同樣非同步。
HashMapConcurrentHashMapHashtable(或包裝器)HashSetLinkedHashSet(插入序)/ TreeSet(自然序)WeakHashMap