hashmap哈希值计算分两步:先调用key.hashcode()获取原始哈希值,再通过扰动函数h ^ (h >>> 16)使高位参与低位运算,提升分布均匀性、减少哈希冲突。

Java 中 HashMap 的哈希值计算分为两步:先对键(key)调用 hashCode(),再通过**哈希扰动函数**(也叫扰动算法)二次处理,目的是让高位参与运算、减少哈希冲突。
1. 初始哈希值:调用 key.hashCode()
所有键对象必须实现 hashCode() 方法。例如 String 类重写了该方法,按字符序列计算出一个整数;Integer 直接返回其数值本身。这个原始值就是“未扰动的哈希值”。
2. 哈希扰动函数:h ^ (h >>> 16)
这是 JDK 7 和 JDK 8 中 HashMap 使用的核心扰动逻辑,定义在 hash(Object key) 方法中:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
说明:
- h >>> 16:将原始哈希值无符号右移 16 位(即丢弃低 16 位,高位补 0)
- 异或运算(^):把原哈希值和右移后的结果逐位异或
- 效果是:让高 16 位“混合”进低 16 位,使低位更充分反映整个哈希值的分布特征
3. 为什么需要扰动?——解决低位信息不足问题
HashMap 底层数组长度总是 2 的幂(如 16、32、64),定位桶位置时使用:
(n - 1) & hash(等价于 hash % n,但更快)
由于 n-1 的二进制全是 1(如 15 是 1111),实际只取 hash 的**最低几位**做索引。如果原始 hashCode() 的低位变化少(比如某些对象的哈希值集中在某一段),就会导致大量元素挤在少数几个桶里。
举例:
假设 hash = 0xAAAA0000(高位有信息,低位全 0),不扰动时 (16-1) & hash = 0,所有这类 key 都落在第 0 号桶;
扰动后:0xAAAA0000 ^ 0x0000AAAA = 0xAAAAAAAA,低位变得随机,分散效果明显提升。
4. JDK 8 的优化补充
除了扰动函数,JDK 8 还引入了红黑树机制:当某个桶中链表长度 ≥ 8 且 table 长度 ≥ 64 时,链表转为红黑树,进一步缓解哈希碰撞带来的性能退化。但扰动函数仍是前置关键步骤,决定“是否容易碰撞”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











