扰动函数的核心作用是让哈希值高位参与索引计算以降低冲突:因(n-1)&hash仅取低几位,原始hashCode高位差异被忽略,易致不同对象映射同桶;扰动函数h^(h>>>16)将高位异或混入低位,提升低位离散性,使桶分布更均匀。

扰动函数的核心作用是让哈希值的高位信息参与索引计算,从而降低数组容量较小时的哈希冲突概率。
为什么原始 hashCode 容易导致冲突
Java 对象的 hashCode() 返回的是一个 32 位整数,但 HashMap 底层数组长度通常是 2 的幂(如默认 16、32、64)。计算下标用的是 (n - 1) & hash,其中 n 是数组长度。当 n = 16 时,n - 1 = 15,二进制是 1111,这个按位与操作只保留 hash 值的低 4 位,高位全部被忽略。
这就带来一个问题:两个不同对象的 hashCode 可能高位差异极大,但低 4 位完全一样,结果映射到同一个桶里——发生哈希冲突。
扰动函数怎么解决这个问题
JDK 1.8 的扰动函数定义为:
立即学习“Java免费学习笔记(深入)”;
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
它把 hashCode 的高 16 位右移后与低 16 位异或,使得高位信息“混合”进低位。即使原始低 4 位相同,经过异或后,新 hash 值的低 4 位大概率不同,从而分散到不同桶中。
- 异或运算具有良好的离散性,能增强哈希值的随机分布
- 右移 16 位是轻量操作,不增加明显开销
- null 键被统一映射到 0 号桶,逻辑清晰且可控
扰动后的 hash 如何定位桶位
得到扰动后的 hash 值后,HashMap 使用 (n - 1) & hash 算下标。因为数组长度 n 总是 2 的幂,n - 1 的二进制全是 1(比如 15 → 1111,31 → 11111),这个位运算等价于对 n 取模,但比除法快得多。
关键在于:扰动让原本被丢弃的高位信息影响了最终的低位结果,使 相同低几位的原始 hashCode 更可能产生不同的桶索引,显著缓解了因低位集中导致的碰撞问题。
不加扰动的实际影响
假设多个字符串的 hashCode 仅在高位不同(常见于简单字符串或自定义 key 实现不当),未扰动时它们会扎堆在少数几个桶里,链表变长,get/put 性能从接近 O(1) 退化为 O(n)。加上扰动后,桶分布更均匀,整体查询效率更稳定。

















