Java完整解析Map

往hashmap存20个元素,会扩容几次?

扩容次数不能只看元素个数,必须同时说明初始容量、负载因子、构造方式以及首次分配发生的时点。

面试Javajava核心题完整解析编辑精选

直接结论

没有给出初始容量与负载因子时,答案不是一个固定数字。以 Java 21 的常见默认配置解释:默认负载因子是 0.75,首次真正插入时才分配默认容量 16 的表,阈值为 12;连续放入 20 个互不覆盖的新键时,第 13 个元素触发容量从 16 扩到 32。因此若把首次建表视为初始化而不是扩容,扩容 1 次;若面试官把从未分配到 16 也计入,则会说发生 1 次初始化加 1 次扩容。应先声明口径。

原理与步骤

HashMap 用容量与负载因子的乘积形成扩容阈值。每次 put 先计算哈希并定位桶;新键实际增加 size 后,如果 size 超过 threshold,就扩大表并重新分布桶。默认构造器并不会立即创建 16 个桶,所以仅从构造代码看不到数组。计算过程应写清:插入 1 到 12 个新键不超过阈值;第 13 个使 size 变为 13,触发 16 到 32;新阈值约为 24;第 20 个仍未超过 24。相同键更新 value 不增加 size,也不会按这个计数触发扩容。

工程场景

工程上应根据可预估元素数预设容量,避免批量装载时连续迁移。例如预计保存 20 个唯一键,可按目标元素数和负载因子反推所需容量,并注意 HashMap 会选择满足要求的二次幂容量。面试回答可以补充:树化、链表长度和桶容量是碰撞处理问题,不等于每次树化都会扩容;高碰撞键、糟糕的 hashCode 或动态增长都会改变运行成本。并发写场景也不应靠调大容量解决,应选择并发容器或外部同步。

验证与边界

验证时用同一 JDK 版本构造默认 HashMap,插入 20 个唯一且哈希分布正常的键,观察 size 与延迟变化;若必须确认内部数组,只能在受控测试中借助诊断工具,业务代码不应依赖私有字段。边界包括指定初始容量、不同负载因子、重复键、删除后再插入、极端碰撞以及 JDK 实现变化。官方 API 只承诺容量和负载因子的性能关系,不承诺所有内部迁移细节,因此回答要区分公共契约与实现观察。

答题练习

  1. 1先声明扩容口径
  2. 2默认阈值 16×0.75=12
  3. 3第 13 个唯一键触发 16 到 32

常见错误

  • 把首次延迟分配和扩容混为一谈
  • 忽略重复键不会增加 size

可能追问

  • 如何为预计元素数计算初始容量
  • 碰撞、树化和扩容分别解决什么问题

来源记录

原始来源
小林coding
来源页面
Java集合面试题
最近收录
2026-07-04
官方复核
Oracle Java 官方文档