请解释 Java 中 HashMap 的工作机制,包括其内部存储结构、哈希冲突的处理方式以及扩容过程。
考察说明
考查对 HashMap 底层实现原理的理解,包括数据结构、哈希算法和扩容机制。
回答思路
- 【回答框架 1】HashMap 基于数组加链表(或红黑树)实现,通过 key 的 hashCode 经过扰动函数后定位到数组索引,数组每个位置存放一个链表或红黑树节点。
- 【回答框架 2】哈希冲突时,新元素会以链表形式挂在同一索引下,当链表长度超过阈值(约 8)且数组容量不小于 64 时,链表会转换为红黑树以提高查询效率。
- 【回答框架 3】HashMap 的容量始终是 2 的幂,这样可以通过 hash 与 (capacity-1) 进行位运算来快速取模,扩容时容量翻倍,元素需重新计算索引位置。
- 【回答框架 4】扩容发生在元素数量超过阈值(容量乘以负载因子,默认 0.75)时,扩容过程会创建新的数组并重新哈希所有元素,这也导致扩容操作较为耗时。
- 【回答框架 5】HashMap 不是线程安全的,多线程环境下可能引发数据不一致或死循环(JDK7 及之前),因此并发场景需使用 ConcurrentHashMap。
- 【关键点 1】HashMap 底层是数组加链表加红黑树。
- 【关键点 2】哈希冲突通过链地址法解决,链表过长时转红黑树。
- 【关键点 3】扩容阈值是容量乘以负载因子,默认负载因子 0.75。
- 【关键点 4】HashMap 非线程安全,并发需使用 ConcurrentHashMap。
- 【易错点 1】不能混淆哈希冲突与哈希碰撞,前者是不同 key 映射到同一索引,后者是 hashCode 相同(更严格)。
- 【易错点 2】链表转红黑树不仅依赖链表长度,还要求数组容量大于等于 64。
- 【易错点 3】扩容并不一定是两倍,而是容量左移一位,但必须保持 2 的幂。