| 項目 | HashMap | Hashtable |
| 線程安全 | 否 | 是(synchronized) |
| 允許 null | key/value 均可 | 均不可 |
| hash 計算 | 單次擾動 + 位運算 | key.hashCode() 直接取模 |
| 繼承體系 | AbstractMap | Dictionary |
| 迭代器 | fail-fast | Enumerator + Iterator |
手寫 MyHashMap 核心實現(教學版)
public class MyHashMap {
static final int DEFAULT_CAPACITY = 16;
static final float LOAD_FACTOR = 0.75f;
transient Node[] table;
int size, threshold;
static class Node {
final Object key;
Object value;
Node next;
int hash;
Node(int h, Object k, Object v, Node n) {
hash = h; key = k; value = v; next = n;
}
}
public MyHashMap() {
table = new Node[DEFAULT_CAPACITY];
threshold = (int)(DEFAULT_CAPACITY * LOAD_FACTOR);
}
int index(Object key) {
return (key.hashCode() ^ (key.hashCode() >>> 16)) & (table.length - 1);
}
public void put(Object key, Object value) {
if (key == null) { putNullValue(value); return; }
int idx = index(key);
for (Node e = table[idx]; e != null; e = e.next) {
if (e.hash == key.hashCode() && (e.key == key || key.equals(e.key))) {
e.value = value; return;
}
}
addNode(idx, key, value, key.hashCode());
}
void addNode(int idx, Object key, Object value, int hash) {
table[idx] = new Node(hash, key, value, table[idx]); // 頭插
if (++size > threshold) resize();
}
void resize() {
Node[] old = table;
table = new Node[old.length * 2];
threshold = (int)(table.length * LOAD_FACTOR);
for (Node e : old) {
while (e != null) {
Node next = e.next;
int idx = index(e.key);
e.next = table[idx];
table[idx] = e;
e = next;
}
}
}
public Object get(Object key) {
if (key == null) return getNullValue();
int idx = index(key);
for (Node e = table[idx]; e != null; e = e.next) {
if (e.hash == key.hashCode() && (e.key == key || key.equals(e.key)))
return e.value;
}
return null;
}
// ... remove, containsKey, size, clear 等
}
面試高頻考點總結
- 為什麼容量是 2 的冪? →
(n-1) & hash 等價取模,均勻分布
- 負載因子 0.75 權衡? → 空間換時間,泊松分布下碰撞概率最低
- JDK 8 為何引入紅黑樹? → 防止惡意構造碰撞導致 O(n) 退化
- 多線程下用什麼? →
ConcurrentHashMap 或 Collections.synchronizedMap
hashCode 與 equals 契約? → 相等必同碼,同碼不必相等
深入理解 HashMap 底層,不僅是面試必備,更是排查生產環境性能問題、選擇正確集合類型的基石。
- 上一篇文章: Selenium 自動化測試:Java 封裝軟斷言實現失敗不中斷、批量驗證最終匯總
- 下一篇文章: Java Calendar 類完整指南:獲取時間字段、日期運算、月份陷阱與最佳實踐
Copyright ©
程式碼之家 All Rights Reserved