Java 面试:HashMap 底层原理怎么答才不乱?

发布时间:2026/6/27 4:09:36

Java 面试:HashMap 底层原理怎么答才不乱? 摘要HashMap是 Java 面试中非常高频的集合类问题。很多人知道它是 key-value 结构也知道 JDK 1.8 后引入了红黑树但面试时容易答散。本文用面试视角简单梳理 HashMap 的底层结构、put 流程、扩容机制、哈希冲突、线程安全问题和常见追问。前言前面两篇文章分别梳理了 Java 集合分类以及ArrayList和LinkedList的区别。这一篇继续讲集合里最常见、也最容易被问深的一个类HashMapHashMap平时开发用得非常多比如根据用户编号查用户信息根据编码映射名称做临时缓存做数据分组做批量查询后的内存匹配。但面试时如果只是回答HashMap 是 key-value 结构。那肯定不够。这篇就用比较短的方式把面试常问点梳理一下。一、面试官一般怎么问HashMap常见问法有这些HashMap底层数据结构是什么HashMap的 put 流程是什么HashMap怎么解决哈希冲突为什么 JDK 1.8 要引入红黑树HashMap默认容量是多少HashMap什么时候扩容HashMap是线程安全的吗HashMap和Hashtable有什么区别HashMap和ConcurrentHashMap有什么区别这篇先讲HashMap本身。二、先给结论HashMap是一种基于哈希表实现的 key-value 集合。JDK 1.8 之后它的底层结构可以简单理解为数组 链表 红黑树其中数组用来定位桶的位置链表用来解决哈希冲突红黑树用来优化链表过长时的查询效率。一句话回答HashMap 底层是数组 链表 红黑树。put 元素时会先根据 key 的 hash 值计算数组下标如果当前位置没有元素就直接放入如果发生哈希冲突就通过 equals 判断 key 是否相同相同则覆盖不同则挂到链表或红黑树上。三、HashMap 底层结构是什么HashMap底层核心是一个数组。数组中的每个位置可以理解成一个桶。每个桶里可能存放一个节点一条链表一棵红黑树。简单理解HashMap ↓ 数组 table ↓ 每个数组位置是一个桶 ↓ 桶里可能是链表或红黑树结构可以简单画成这样table[0] - null table[1] - Node table[2] - Node - Node - Node table[3] - TreeNode也就是说HashMap 不是单纯的数组也不是单纯的链表而是数组、链表、红黑树结合使用。四、HashMap 为什么查询快因为它不是从头遍历所有元素。它会先根据 key 的 hash 值计算出数组下标。比如map.get(user001);大致过程是计算 key 的 hash ↓ 根据 hash 定位数组下标 ↓ 到对应桶里查找如果桶里只有一个元素直接判断 key 是否相等即可。如果桶里是链表就沿着链表查找。如果桶里是红黑树就按树结构查找。所以 HashMap 的平均查询效率比较高。五、put 方法大概流程面试时put流程是高频点。可以按下面这个顺序答。1. 计算 key 的 hash 值先根据 key 计算 hash。hash hash(key)2. 根据 hash 计算数组下标通过 hash 和数组长度计算桶位置。index hash (length - 1)3. 判断当前位置是否为空如果这个桶是空的直接放入新节点。table[index] null直接新增。4. 如果当前位置不为空说明发生了哈希冲突这时要继续判断key 是否相同如果相同覆盖旧值如果不同挂到链表或红黑树上。5. 插入后判断是否需要扩容如果元素数量超过阈值就触发扩容。六、什么是哈希冲突不同的 key计算出来的数组下标可能一样。这就是哈希冲突。比如key1 - index 3 key2 - index 3两个 key 都要放到同一个桶里就冲突了。HashMap解决冲突的方式是链表 红黑树JDK 1.8 之前主要是数组 链表。JDK 1.8 之后如果链表过长会转成红黑树。七、什么时候链表会转红黑树JDK 1.8 中链表转红黑树有两个重要条件链表长度大于等于 8 数组长度大于等于 64也就是说不是链表长度到了 8 就一定树化。还要看数组容量是否达到 64。如果数组还比较小通常会优先扩容而不是直接树化。简单记链表长度 8并且数组长度 64才会转红黑树。为什么要这样设计因为数组还小的时候冲突可能是容量太小导致的。这时扩容比树化更合适。八、为什么要引入红黑树链表查询是从头往后找。如果链表很长查询效率会下降。链表查询时间复杂度是O(n)红黑树查询效率更稳定O(log n)所以当某个桶里的链表太长时转成红黑树可以提升查询效率。一句话红黑树是为了解决哈希冲突严重时链表过长导致查询性能下降的问题。九、HashMap 默认容量和负载因子HashMap默认初始容量是16默认负载因子是0.75扩容阈值是容量 * 负载因子所以默认情况下16 * 0.75 12也就是说当 HashMap 中的元素数量超过 12 时就会触发扩容。十、HashMap 怎么扩容HashMap扩容时容量一般会变成原来的 2 倍。比如16 - 32 - 64 - 128扩容不是简单改一个数字。它需要把原来的数据重新分布到新数组中。所以扩容是有成本的。如果一开始就知道大概会放多少数据可以指定初始容量。比如MapString, String map new HashMap(128);这样可以减少扩容次数。十一、为什么容量要是 2 的幂HashMap的数组长度一般是 2 的幂。比如16、32、64、128这样做主要是为了让下标计算更高效。HashMap 计算下标时常见方式是index hash (length - 1)当 length 是 2 的幂时这种位运算可以比较均匀地分布数据也比取模运算更高效。面试时可以这样说HashMap 容量使用 2 的幂是为了配合 hash (length - 1) 计算数组下标提高计算效率同时让元素分布相对均匀。十二、HashMap 是线程安全的吗不是。HashMap不是线程安全的。如果多个线程同时修改同一个HashMap可能出现数据覆盖数据丢失读取到脏数据扩容时出现异常问题。所以多线程共享修改场景不建议直接使用HashMap。可以考虑ConcurrentHashMap加锁使用局部变量避免多线程共享常见回答HashMap 不是线程安全的适合单线程或局部变量场景。如果多个线程同时读写同一个 Map应该考虑 ConcurrentHashMap 或额外加锁。十三、HashMap 可以存 null 吗可以。HashMap允许一个 null key多个 null value。示例MapString, String map new HashMap(); map.put(null, default); map.put(name, null);但需要注意key只能有一个 null。因为 key 不能重复。十四、HashMap 和 Hashtable 有什么区别这个也是经典面试题。简单对比对比项HashMapHashtable线程安全不安全安全性能较好较差null key/value允许不允许出现时间较新较老常用程度常用很少用一句话回答HashMap 不是线程安全的允许 null key 和 null value性能更好实际开发中更常用。Hashtable 是早期集合类方法使用 synchronized 保证线程安全但性能较差而且不允许 null key 和 null value现在用得比较少。十五、HashMap 和 ConcurrentHashMap 有什么区别简单说HashMap不是线程安全的。ConcurrentHashMap是线程安全的适合并发场景。在多线程环境下如果多个线程会同时修改 Map一般使用ConcurrentHashMap。示例MapString, String map new ConcurrentHashMap();面试时可以这样答HashMap 适合单线程或局部变量场景ConcurrentHashMap 适合多线程并发读写场景。它通过更细粒度的并发控制来保证线程安全同时尽量减少锁竞争。十六、项目里常见怎么用 HashMap实际开发中HashMap最常见的用法不是炫底层而是提升查询效率。比如先批量查数据再转成 Map避免循环查库。示例ListUser users userService.queryByIds(userIds); MapLong, User userMap users.stream() .collect(Collectors.toMap(User::getId, item - item));后面使用时User user userMap.get(userId);这种写法很常见。尤其是在批处理、数据组装、报表统计里经常会用 Map 做内存匹配。但要注意如果 key 可能重复要处理合并逻辑。比如MapLong, User userMap users.stream() .collect(Collectors.toMap( User::getId, item - item, (oldValue, newValue) - oldValue ));否则 key 重复时会报错。十七、面试回答模板如果面试官问HashMap 底层原理了解吗可以这样回答HashMap 是基于哈希表实现的 key-value 集合。 JDK 1.8 之后底层主要是数组 链表 红黑树。put 元素时会先根据 key 计算 hash 值再通过 hash 和数组长度计算出桶下标。 如果当前位置没有元素就直接放入如果当前位置已经有元素说明发生了哈希冲突就会比较 key 是否相同相同则覆盖 value不同则挂到链表或红黑树上。 当链表长度达到一定条件并且数组容量足够大时链表会转成红黑树主要是为了避免链表过长导致查询效率下降。 HashMap 默认容量是 16负载因子是 0.75超过阈值后会扩容扩容一般是原来的 2 倍。 另外HashMap 不是线程安全的多线程并发修改时应该使用 ConcurrentHashMap 或额外加锁。这段基本就够用了。十八、一句话总结HashMap底层是数组 链表 红黑树它通过 hash 定位数组下标通过链表或红黑树解决哈希冲突。面试时不要只说HashMap 是 key-value 结构更好的回答是HashMap 的核心是哈希定位、冲突处理、扩容机制和线程安全问题。把这几个点讲清楚基本就不会乱。大家加油

相关新闻