Map 介面
Map<String, String> map = new HashMap<>();
map.put(null, "null鍵測試"); // 允許 null key
map.put("key", null); // 允許 null value
map.put(null, null); // 覆蓋前值,返回舊值
System.out.println(map.get(null)); // 讀取 null key 對應值
class MyKey {
String name;
MyKey(String n) { this.name = n; }
@Override public int hashCode() { return name.hashCode(); }
@Override public boolean equals(Object o) { ... }
@Override public String toString() { return name; }
}
// 正確用法
Map<MyKey, String> map = new HashMap<>();
MyKey k1 = new MyKey("key1");
map.put(k1, "value1");
System.out.println(map.get(k1)); // "value1"
// 危險操作:修改 Key 內部狀態導致 hashCode 改變
k1.setName("key1-modified"); // 假設有 setter
System.out.println(map.get(k1)); // null!無法找到原 Entry
// 正確更新流程
map.remove(k1);
k1.setName("key1-modified");
map.put(k1, "newValue");
鐵律:Map 的 Key 物件一旦放入,絕不可修改其 hashCode()/equals() 依賴的欄位。建議 Key 使用不可變類(如 String、Integer、自訂不可變類)。
// 方式 1:keySet 迭代(推薦單純遍歷 Key)
for (String key : map.keySet()) { ... }
// 方式 2:entrySet 迭代(推薦需同時取 Key/Value,避免二次查找)
for (Map.Entry<String, String> entry : map.entrySet()) {
String k = entry.getKey();
String v = entry.getValue();
}
// 方式 3:forEach (JDK 8+)
map.forEach((k, v) -> System.out.println(k + "=" + v));
// 迭代中移除:必須用 Iterator.remove()
Iterator<Map.Entry<K,V>> it = map.entrySet().iterator();
while (it.hasNext()) {
if (condition(it.next())) it.remove();
}
// 計算模式 (JDK 8+)
map.computeIfAbsent("key", k -> expensiveCompute());
map.merge("key", "suffix", (old, v) -> old + v);
| 考點 | 核心答案 |
|---|---|
| 擴容機制 | 容量達到 threshold (capacity * loadFactor) 時擴容 2 倍,JDK 8 低位掩碼重新分佈,高位不動或遷移 |
| 紅黑樹轉換閾值 | 鏈表長度 ≥ 8 且容量 ≥ 64 轉紅黑樹;縮容 ≤ 6 退化鏈表 |
| hashCode 擾動函數 | h ^ (h >>> 16) 讓高位參與運算,減少衝突 |
| 為何容量是 2 的冪次 | 位運算 (n-1) & hash 替代取模,效能極高 |
| 線程不安全表現 | 多執行緒 put 導致鏈表成環、數據丟失、CPU 100% |
new HashMap<>(expectedSize) 避免頻繁擴容。hashCode()/equals()。ConcurrentHashMap 或 Collections.synchronizedMap()。Iterator.remove(),JDK 8+ 用 removeIf()。computeIfAbsent/merge 簡化「查詢-計算-存入」邏輯。HashMap 是 Java 開發中使用頻率最高的集合類。深入理解其雜湊算法、擴容機制、紅黑樹優化、Key 不變性約束,能幫助你寫出高效、無 Bug 的代碼,也是面試必考的核心知識點。