HashMap哈希计算先对key.hashCode()执行扰动函数h^(h>>>16),使高16位参与低位运算,再通过(n-1)&hash定位下标,从而减少冲突、提升分布均匀性。

Java HashMap 的哈希值计算和扰动函数,核心在于 让 key 的 hashCode 经过扰动后,高位也参与低位的散列运算,从而减少哈希冲突、提升桶分布均匀性。JDK 8 中的扰动函数就是那行经典代码:(h = key.hashCode()) ^ (h >>> 16)。
HashMap 怎么计算哈希值(hash 值)
HashMap 并不直接使用 key.hashCode() 作为数组下标,而是先对它做一次「扰动」,再与数组长度减一(table.length - 1)做按位与运算,得到最终索引位置。
完整哈希计算流程如下:
- 调用
key.hashCode()得到原始哈希码(32 位 int) - 执行扰动函数:
h ^ (h >>> 16),即高 16 位异或低 16 位 - 用扰动后的值对数组长度取模:但实际用的是
(n - 1) & hash(n 是 2 的幂),等价于取模且更高效
为什么需要扰动函数?
很多对象的 hashCode() 实现只依赖低几位字段(比如 String 常基于字符累加,低位变化多、高位常为 0),若直接用 hashCode() % table.length,会导致大量 key 映射到相同桶中——因为 table.length 通常较小(如 16、32),只用低几位决定位置,高位被完全忽略。
立即学习“Java免费学习笔记(深入)”;
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
扰动函数 h ^ (h >>> 16) 把高 16 位「混合」进低 16 位,让高位信息也影响最终索引,显著改善散列质量。
例如:
原始 hash = 0xAAAA0000(高 16 位是 0xAAAA,低 16 位全 0)
右移 16 位后 = 0x0000AAAA
异或结果 = 0xAAAA0000 ^ 0x0000AAAA = 0xAAAAAAAA → 低位不再为 0,参与寻址。
扰动函数怎么写(手写实现)
你不需要自己重写 HashMap 的 hash 方法,但如果要模仿或调试,可以这样写一个等效函数:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
注意几点:
- key 为 null 时,约定 hash 值为 0(null 总放在数组第 0 个桶)
-
>>>是无符号右移,确保高位补 0,避免负数干扰 - 这个扰动只做一次,不是循环多次;实测表明一次已足够平衡
小结:关键就两点
HashMap 的哈希设计不是追求加密级散列,而是「快 + 均匀」:
- 扰动函数用
^ (h >>> 16)快速融合高位信息 - 寻址用
(n - 1) & hash替代取模,要求容量始终是 2 的幂(扩容时自动保证)

















