hashmap容量必须是2的幂次方,以支持位运算索引计算、提升哈希分布均匀性、实现扩容时免重哈希;初始容量会自动对齐到最近的2的幂。

HashMap 底层用数组 + 链表(或红黑树)存储键值对,核心是通过哈希值快速定位桶(bucket)。容量必须是 2 的幂次方,不是约定俗成,而是为了支撑三项关键机制:索引计算快、分布更均匀、扩容迁移高效。
索引计算靠位运算,不是取模
HashMap 不用 hash % table.length 算下标,而是用 (table.length - 1) & hash。这个操作成立的前提是 table.length 是 2 的幂——此时 length−1 的二进制全是 1(比如 16→15 是 1111,32→31 是 11111),按位与就等价于只保留 hash 的低几位,效果和取模一致,但位运算速度通常快 3~5 倍。
如果设成非 2 幂容量(如 10),length−1=9(1001₂),中间的 0 会屏蔽 hash 的某些位,导致多个不同 hash 映射到同一索引,人为加剧冲突。
哈希分布更充分,避免桶空转
当 length−1 的二进制含 0(如 1001),那些对应位置的 hash 位无论 0 或 1,结果都不变。例如用 10 做容量,第二、三位恒被忽略,大量 key 就会挤在索引 0、2、8 这类偶数位,奇数位长期空置——相当于一半空间废掉,链表拉长,查询退化为 O(n)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
而 length=16(1111₂),低 4 位全参与运算,hash 的微小变化能充分反映到索引上,分布自然更散、更均衡。
扩容时免重哈希,仅看高位bit
扩容从 16→32,新掩码是 31(11111₂),比旧掩码 15(01111₂)多一位。每个元素只需检查 hash 的新增最高位(第 5 位,从 0 开始):
- 该位为 0 → 新索引 = 原索引
- 该位为 1 → 新索引 = 原索引 + 旧容量(即 +16)
不需要重新调用 hashCode(),也不用再算一遍 hash % 新长度,迁移吞吐量大幅提升。这个逻辑只有容量翻倍(即始终维持 2ⁿ)才能成立。
初始容量自动对齐,用户无需操心
即使你写 new HashMap(10),内部会调用 tableSizeFor(10),算出最近的 2 的幂(16);传入 100 → 得到 128。这是强制转换,不是建议。整个机制从初始化起就闭环保障——所有实例天然适配上述三项优化。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










