初始容量默认为16且必须是2的幂,负载因子默认0.75;前者影响数组大小与扩容频率,后者决定扩容阈值,共同权衡时间与空间性能。

HashMap的初始容量和负载因子,直接决定了它内部数组的大小以及何时触发扩容,是影响性能的关键参数。
初始容量(initialCapacity)
这是HashMap创建时底层哈希表数组的长度,默认为16。它必须是2的幂次方(如16、32、64),因为HashMap通过位运算(hash & (capacity - 1))快速计算索引,前提是capacity为2的幂。
- 如果预估要存入100个键值对,设初始容量为128比用默认16更合理——避免频繁扩容
- 构造时传入非2的幂的数(如20),HashMap会自动向上取最近的2的幂(即32)
- 容量太小 → 扩容频繁(rehash开销大);太大 → 内存浪费、遍历链表/红黑树时缓存不友好
负载因子(loadFactor)
这是一个浮点数,默认为0.75,表示“数组填满程度”的阈值。当元素个数 > 容量 × 负载因子时,HashMap就会扩容(通常是翻倍)并重新散列所有元素。
- 0.75是时间与空间的平衡选择:过高(如0.9)→ 冲突增多,链表变长,查找退化为O(n);过低(如0.5)→ 提前扩容,内存占用高,但冲突少
- 如果读多写少且内存充足,可适当调低负载因子(如0.6)来减少哈希冲突
- 如果内存敏感且数据分布均匀,也可略提高(如0.8),但需实测验证性能影响
扩容机制与实际影响
扩容不是简单扩大数组,而是重建整个哈希表:申请新数组、重新计算每个Entry的哈希位置、搬运数据。这个过程在单线程下是阻塞的,且耗时与当前元素总数成正比。
立即学习“Java免费学习笔记(深入)”;
- 例如:容量16 × 负载因子0.75 = 阈值12 → 第13个元素插入时触发扩容到32
- 连续插入场景下,若初始容量设为0,构造器会用默认16;但若明确知道数据量,建议显式指定(如new HashMap(200))
- JDK 8中,当链表长度≥8且数组长度≥64时,链表转为红黑树,缓解最坏情况下的性能退化
怎么选才合适?
没有万能值,关键看你的使用场景:
- 已知精确数量N:初始容量设为大于等于 N / 0.75 的最小2的幂(如N=100 → 100/0.75≈133.3 → 取128或256)
- 不确定数量但偏小(
- 高频并发写入:考虑ConcurrentHashMap,它分段锁+更细粒度扩容,不依赖单一loadFactor
- 注意:负载因子只影响扩容时机,不影响get/put的平均时间复杂度(仍是O(1)均摊)











