必须是2的幂,因n=2ᵏ时n−1二进制全为1,(n−1)&hash等价于hash%n且仅保留hash低k位,实现高效索引定位;同时支持扰动函数和扩容时免重哈希。

Java HashMap 用 (n - 1) & hash 替代 hash % n,核心前提是数组长度 n 必须是 2 的幂。这不是炫技,而是基于二进制本质的硬优化——位运算直接操作内存比特,比取模所需的除法指令快得多。
为什么必须是 2 的幂?
当 n = 2k 时:
- n 的二进制是 1 后跟 k 个 0(例如 16 → 10000)
- n - 1 的二进制就是 k 个 1(例如 15 → 01111)
- 此时 hash & (n - 1) 等价于只保留 hash 的低 k 位,恰好就是 hash % n 的结果
位运算怎么算索引?
假设默认容量 n = 16(即 2⁴),那么 n - 1 = 15(二进制 01111):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 任意 hash 值(比如 1027,二进制 10000000011)和 15 做 & 运算,只取最后 4 位 → 0011 = 3
- 结果恒在 [0, 15] 范围内,天然完成“取模”效果
- 没有除法、没有取余、不转十进制,CPU 一个周期就能出结果
光有位运算还不够:hash 值也要预处理
直接用 key.hashCode() 的低几位做 & 运算容易冲突(比如 String 的哈希值低位常相似)。所以 HashMap 先做扰动:
- h ^ (h >>> 16):把高 16 位右移后与低 16 位异或
- 让高位信息“掺入”低位,提升低位分布的随机性
- 再用 (n - 1) & 扰动后的 hash,大幅降低桶碰撞概率
扩容时也靠位运算省事
扩容为原容量 2 倍(如 16→32)后,新索引只需判断原 hash 的第 5 位(oldCap 位)是否为 1:
- 若 hash & oldCap == 0 → 新索引 = 原索引
- 否则 → 新索引 = 原索引 + oldCap
- 全程不用重新调用 hash() 或 % 运算,迁移效率翻倍
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










