HashMap扰动函数核心目标是让高位参与下标计算以降低哈希冲突;JDK8采用h ^ (h >>> 16)异或右移方式,通过将高16位与低16位异或,使高位信息影响最终索引,提升分布均匀性。

Java 中 HashMap 的扰动函数(也叫哈希扰动)核心目标是让原始哈希值的高位参与下标计算,避免只依赖低位导致大量哈希冲突。JDK 8 及之后采用的是经典的 异或右移 扰动方式,设计简洁且高效。
为什么需要高位参与?
HashMap 底层数组长度总是 2 的幂(如 16、32、64),计算索引用的是 (n - 1) & hash(即取低 log₂(n) 位)。若原始 hash 值仅低位有变化(比如对象默认 hashCode 是内存地址,低位常重复),高位差异被完全丢弃,会导致不同对象映射到同一桶,加剧碰撞。
JDK 8 的扰动函数:hash() 方法
源码中关键逻辑为:
static final int hash(Object key) {int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
这个设计让高位“混合”进低位:
立即学习“Java免费学习笔记(深入)”;
- 右移 16 位:把高 16 位移到低 16 位位置(无符号,补 0)
- 与原 hash 异或:低 16 位 = 原低 16 位 ^ 原高 16 位,使高位信息影响最终参与取模的低位
- 即使数组容量小(如初始 16,只取低 4 位),这 4 位也已融合了原始 hash 的第 4~19 位信息
为什么选异或而非加法或乘法?
异或具备以下优势:
- 可逆性弱但分布好:避免加法可能带来的进位集中、乘法引入额外开销
- 零成本位运算:CPU 级别支持,无溢出、无分支、无内存访问
- 保持低位敏感性:若原 hash 低 4 位不同,异或后低 4 位大概率仍不同(除非对应高位也恰好相同)
实际效果示例
假设 key.hashCode() = 0x12345678(十进制 305419896):
- 原低 4 位 = 1000(8)
- 右移 16 位 → 0x00001234
- 异或结果 = 0x12345678 ^ 0x00001234 = 0x1234444C
- 对 length=16(0xF)取索引 → 0x1234444C & 0xF = 0xC(12)
- 可见结果不再只由 0x78 决定,而是受 0x1234 显著影响


















