(n−1)&hash能替代hash%n,因n为2的幂时n−1二进制全为1,位与操作等价于取hash低log₂n位,速度远快于取模;若n非2的幂则索引分布失衡、冲突剧增。

因为这是用位运算高效替代取模运算的方案,前提是数组长度 n 必须是 2 的幂次方。
为什么不用 hash % n
取模运算本质是除法,CPU 执行开销大;而位与运算(&)直接操作二进制位,速度通常快十几倍甚至更多。在高频 put 操作中,这点差异会显著影响整体性能。
为什么 (n - 1) & hash 等价于 hash % n
当 n 是 2 的幂(如 16、32、64),n−1 的二进制全是 1(例如 16−1 = 15 → 1111)。此时 (n−1) & hash 实际就是保留 hash 的低 k 位,恰好等于 hash 对 n 取余的结果。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- n = 16 → n−1 = 15 = 000011112 → 保留 hash 最低 4 位
- n = 32 → n−1 = 31 = 000111112 → 保留最低 5 位
如果不满足 2 的幂,会发生什么
比如 n = 10,n−1 = 9 = 10012,那么 (n−1) & hash 只保留 hash 的第 0 位和第 3 位,其余位被强制清零。这会导致:
- 大量哈希值映射到极少数下标(如 0、1、8、9)
- 其他桶长期空置,分布严重倾斜
- 冲突剧增,链表/红黑树变长,查找退化为 O(n)
它还依赖扰动函数协同工作
HashMap 先对原始 hashCode 做扰动:hash = h ^ (h >>> 16),把高 16 位混入低 16 位。否则仅靠低位参与 & 运算,容易因高位不同、低位相同而频繁碰撞(比如两个 key 的 hashCode 仅高位不同,低 4 位都是 1010,就会都落到下标 10)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










