Entry<K,V>[] table)本文基於 JDK 7 源碼(經典教學版)逐行剖析。
static final int DEFAULT_INITIAL_CAPACITY = 16; // 必須 2^n
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
transient Entry<K,V>[] table;
transient int size;
int threshold; // capacity * loadFactor
final float loadFactor;
transient volatile int modCount; // fail-fast
HashMap():默認 16/0.75,threshold=12;HashMap(int cap):指定容量,自動向上取 2 的冪;HashMap(int cap, float lf):完全自定義,參數校驗;HashMap(Map<? extends K,? extends V> m):複製構造,預分配容量避免擴容。putForNullKey()(固定放 table[0]);hash(key.hashCode()) 計算擾動 hash;indexFor(hash, table.length) 定位桶索引;e.hash == hash && (e.key==key || key.equals(e.key)) → 替換 value,返回舊值;addEntry() 頭插法插入新 Entry,modCount++,size++;size > threshold → resize(2*capacity)。h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
目的:將高位信息混入低位,減少碰撞,配合 & (length-1) 實現近似均勻分布。
return h & (length - 1);
為何 capacity 必須 2^n?
length-1 二進制全為 1(如 15=1111),& 運算相當於取模,且極快。驗證:1000 個 key 在 capacity=16 時均勻分佈 16 桶;capacity=50 時僅落入 8 個桶,嚴重失衡。
indexFor(e.hash, newCap)(rehash);getForNullKey() 掃 table[0];prev/e 遍歷;prev.next = e.next 或 table[i] = e.next 斷鏈;modCount++、size--、調用 recordRemoval()。HashMap 非線程安全,多線程下:
替代方案:
Collections.synchronizedMap() 或 Hashtable(鎖整張表,性能差);new HashMap((int)(n/0.75)+1) 避免擴容;ConcurrentHashMap;hashCode()/equals(),遵守協定:equals 真 → hashCode 必相等。