hashmap底层数组容量必须是2的幂次方,以支持(n-1)&hash高效替代hash%n、保障哈希分布均匀、实现扩容时免重哈希;传入非2幂值会自动规整为最近的2幂。

HashMap 底层数组初始容量必须是 2 的幂次方,核心是为了用位运算 (n - 1) & hash 高效、准确地替代取模运算 hash % n,同时保障哈希分布均匀和扩容过程轻量。
定位下标:用 & 替代 %,靠的是二进制全 1
数组下标计算公式是 i = (n - 1) & hash,它能等价于 hash % n 的前提是:n 是 2 的幂次方。因为此时 n−1 二进制表示全是 1(如 16→15=1111,32→31=11111),位与操作就相当于只保留 hash 的低几位——数学上完全等同于对 n 取模,但 CPU 执行位与比整数除法快一个数量级。
- 若 n = 16(2⁴),n−1 = 15(二进制 00001111),& 运算只取 hash 低 4 位 → 结果范围 [0,15]
- 若 n = 15(非 2ⁿ),n−1 = 14(二进制 00001110),& 运算会强制屏蔽第 0 位(最低位),导致结果永远为偶数 → 下标 1、3、5… 永远为空,空间浪费且冲突激增
哈希分布:避免低位失效,提升散列质量
单纯用 key.hashCode() 直接取低位容易造成大量重复(比如对象 ID 末位趋同)。HashMap 加入了扰动函数:h = h ^ (h >>> 16),把高 16 位异或混入低 16 位。当容量是 2ⁿ 时,(n−1) & hash 就能真正利用到这些“揉过”的低位信息;否则,非 2ⁿ 的掩码(如 14=1110)会丢弃关键比特,让扰动失效,加剧聚集。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 例如:hashCode=0xAAAA0000,右移异或后变成 0xAAAAFFFF;若用 n=16,&15 可取到丰富变化的低 4 位
- 若误用 n=12,n−1=11(1011),则第 1 位恒被清零,部分差异被抹平
扩容迁移:单比特判断,免重哈希
容量从 16→32、32→64……翻倍时,新旧容量都满足 2ⁿ,因此新下标只需看 hash 在新增高位上是 0 还是 1:
- 是 0 → 元素留在原位置
- 是 1 → 新位置 = 原位置 + 旧容量
- 无需重新调用 hashCode() 或执行完整 hash 计算,链表/红黑树迁移也只需按顺序拆成两段
若容量不是 2ⁿ(如 17→34),就无法做这种位级分流,必须全量重散列,性能断崖式下跌。
初始化容错:传啥都给你规整成 2 的幂
你写 new HashMap(10) 或 new HashMap(100),底层会自动调用 tableSizeFor(),找到 ≥ 输入值的最小 2ⁿ(分别是 16 和 128)。所以“必须是 2 的幂”不是使用者的硬约束,而是 HashMap 内部强保证的设计契约——所有实际容量只能是 16、32、64…直到 2³⁰。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










