
Java HashMap 面试别只背 16、0.75、8、64,本文把容量、扩容、碰撞、树化和并发边界串成一套能经得起追问的回答。
HashMap 的公开契约是:它基于哈希表实现 Map,允许 null 键和值;默认负载因子是 0.75。当条目数超过「负载因子 × 当前容量」时,会发生 rehash,容量大约翻倍。get 和 put 只有在哈希函数把元素分布得比较均匀时,才具有常数时间表现。1| 名称 | 面试时怎么解释 | 常见误说 |
|---|---|---|
capacity | 当前哈希表的桶数量 | 把它说成键值对数量 |
load factor | 允许表被填充到什么程度后触发扩容的比例 | 把 0.75 说成固定容量 |
threshold | 触发扩容的条目数上限,通常和 capacity × load factor 相关 | 把阈值直接当成桶数量 |
16,默认负载因子是 0.75。因此,第一次真正初始化为 16 个桶时,阈值通常是 12。但这几个数字属于实现与构造参数共同决定的结果,不能把它们当成 HashMap 接口层面的永久保证。2容量是桶的数量,负载因子是扩容比例,阈值是触发扩容的条目数。默认构造下,当前 OpenJDK 使用 16 的初始容量和 0.75 的负载因子,第一次初始化后阈值通常是 12;如果指定了初始容量,实际容量还会按实现规则调整。
put 的关键不是「每插入一个元素就扩容」,而是先把元素放入对应桶;当 size 超过阈值时,当前 OpenJDK 才调用 resize()。扩容时,新表容量通常是旧表的两倍,然后把旧桶中的节点迁移到新表。2Map<String, Integer> scores = new HashMap<>(16);
for (int i = 0; i < 13; i++) {
scores.put("user-" + i, i);
}put 上,不能把单次操作永远概括成常数时间;从一段连续操作的平均表现看,哈希表仍可保持较好的摊销效率,但这取决于实现和哈希分布。treeifyBin;但如果整张表的容量小于 64,源码会优先 resize(),而不是直接树化。只有表容量达到最小树化容量后,才会把该桶的链表节点转换成树节点。28。64;否则先扩容。HashMap 的 O(1) 说成无条件保证O(1)。1hashCode 分布很差,或者可变键在放入后改变了参与哈希的字段,查找行为就可能偏离预期。HashMap 源码,而是知道键的契约必须稳定。一个简单的反问自测是:如果对象放入HashMap后,参与equals和hashCode的字段变了,还能不能可靠地用原对象取出?
HashMap 是非同步的。如果多个线程并发访问,且至少一个线程会结构性修改映射,就需要外部同步;添加或删除映射属于结构性修改,只修改已有键对应的值不属于结构性修改。它的迭代器可能在结构性修改后抛出 ConcurrentModificationException,但官方明确说这是 best-effort,不能依赖这个异常保证程序正确。1| 说法 | 是否正确 | 原因 |
|---|---|---|
| 迭代器可能 fail-fast | 基本正确 | 这是迭代期间检测到结构性修改的提示机制,而且只是 best-effort |
HashMap 适合多线程同时写 | 错误 | 它本身不是同步容器,需要外部同步 |
出现 ConcurrentModificationException 就说明数据安全 | 错误 | 异常不是并发正确性保证 |
单线程或已经由外部锁保护的场景可以使用 HashMap;需要并发读写时,要根据复合操作和一致性要求选择同步包装或 ConcurrentHashMap。fail-fast 只能帮助发现部分错误用法,不能代替同步策略。
HashMap 是基于哈希表的 Map 实现,默认负载因子是 0.75。容量指桶数量,阈值是触发扩容的条目数,默认构造下当前 OpenJDK 第一次初始化通常是 16 个桶、阈值 12。插入后如果 size 超过阈值,会触发 resize,容量通常翻倍并迁移节点。多个键落到同一个桶就是碰撞,桶内节点达到树化阈值时不一定立刻树化,因为表容量小于 64 时当前实现会先扩容。get 和 put 的常数时间表现依赖哈希分布,不能绝对化。最后,HashMap 非同步,fail-fast 也不是线程安全保证;并发读写要考虑外部同步或 ConcurrentHashMap,并注意后者不接受 null 键和值。
capacity、load factor 和 threshold?O(1) 说成了依赖哈希分布的常数时间表现?null 键值上的差异?docs.oracle.com
github.com
docs.oracle.com
This story was produced automatically by a channel. One sentence is all it takes for Neodrop to keep producing for you.