一篇看懂 Java HashMap 原理:底层结构、存取流程与面试高频考点

张开发
2026/4/18 18:46:20 15 分钟阅读

分享文章

一篇看懂 Java HashMap 原理:底层结构、存取流程与面试高频考点
一篇看懂 Java HashMap 原理底层结构、存取流程与面试高频考点HashMap 是 Java 集合框架中最常用、面试出镜率最高的实现类以**键值对Key-Value**形式存储数据具备查询快、插入快、删除快的特点但线程不安全、不保证有序。本文从底层结构、哈希计算、存取流程、扩容机制、常见问题等方面彻底讲透 HashMap 原理。一、HashMap 核心定位- 存储形式 key → value 映射key 唯一、允许为 null最多一个 null key多个 null value- 线程安全非线程安全多线程下建议用 ConcurrentHashMap- 有序性不保证插入顺序遍历顺序随扩容可能变化- 底层结构- JDK 1.7数组 链表- JDK 1.8数组 链表 红黑树链表过长自动转树提升查询效率二、底层数据结构详解1. 核心组成1. 哈希表数组- 是 HashMap 的主体称为“桶bucket”- 下标由 key 的哈希值计算得出是 O(1) 定位的基础2. 链表- 解决哈希冲突不同 key 算出相同下标时用链表串起来3. 红黑树- JDK 1.8 新增当链表长度 ≥ 8 且数组长度 ≥ 64 时自动转为红黑树- 目的避免长链表导致查询退化为 O(n)红黑树查询为 O(logn)2. 关键常量JDK 1.8- 默认初始容量 16 必须是 2 的 n 次方- 默认加载因子 0.75 时间与空间平衡的经验值- 树化阈值 8 链表转红黑树- 解树阈值 6 红黑树退化为链表- 最小树化容量 64 数组长度不足 64 优先扩容不树化三、哈希计算与下标定位核心1. 哈希值计算HashMap 不直接使用 hashCode() 而是做一次扰动函数javastatic final int hash(Object key) {int h;return (key null) ? 0 : (h key.hashCode()) ^ (h 16);}- 高 16 位与低 16 位异或让哈希分布更均匀减少冲突- key null 固定存在下标 0 位置2. 数组下标计算javaindex hash (table.length - 1)- 等价于取模但位运算更快- 因为数组长度永远是 2 的 n 次方 length-1 低位全 1保证下标分布均匀四、put 存值完整流程JDK 1.81. 数组为空时执行第一次扩容初始化容量为 162. 根据 key 计算哈希值与数组下标3. 如果当前桶为空直接新建节点放入4. 如果桶不为空- 若 key 已存在覆盖旧 value- 若是红黑树执行树的插入- 若是链表尾插法追加JDK 1.7 是头插5. 链表长度 ≥ 8 且数组长度 ≥ 64链表转红黑树6. 插入后判断元素数量 阈值容量 × 加载因子执行扩容五、get 取值流程1. 根据 key 计算哈希与下标2. 定位到对应桶3. 首节点 key 匹配直接返回 value4. 若是红黑树树中查找5. 若是链表遍历查找6. 找不到返回 null六、扩容机制最关键考点1. 什么时候扩容- 元素个数 容量 × 加载因子默认 16 × 0.75 12- 数组长度不足树化前优先扩容2. 扩容做什么- 新建数组容量变为原来 2 倍- 重新计算所有节点下标迁移到新数组- JDK 1.8 优化节点要么在原下标要么在 原下标 旧容量无需重新全部 hash3. 为什么长度必须是 2 的 n 次方1. 下标计算 hash (len-1) 效率极高2. 扩容时重新分配下标更简单、均匀3. 减少哈希冲突提高查询效率七、哈希冲突与解决办法1. 什么是哈希冲突不同 key 计算出相同数组下标称为冲突。2. HashMap 解决方案- JDK 1.7链地址法 头插法- JDK 1.8链地址法 尾插法 红黑树- 配合扰动函数、2 次方位运算尽量减少冲突八、JDK 1.7 与 JDK 1.8 区别必背1. 结构1.7 数组链表1.8 数组链表红黑树2. 插入1.7 头插1.8 尾插避免多线程扩容链表成环3. 扩容重 hash1.7 重新计算1.8 简化迁移规则4. 哈希冲突1.8 长链表性能大幅提升5. 并发风险1.7 扩容可能链表成环、死循环1.8 仍非线程安全九、高频面试问题总结1. HashMap 线程不安全表现- 数据覆盖、丢失- JDK 1.7 扩容可能出现链表环导致 CPU 100%2. 为什么加载因子是 0.75- 冲突概率、空间利用率、性能三者平衡泊松分布统计经验值3. HashMap、HashTable、ConcurrentHashMap 区别- HashTable线程安全全表锁、效率低、不允许 null key/value- ConcurrentHashMap线程安全、分段锁/ CAS synchronized、高并发4. 为什么重写 equals 必须重写 hashCode- 相等对象必须有相同 hashCode否则 HashMap 无法正常存取5. HashMap 如何保证 key 唯一- 先比较 hashCode再用 equals 判断相同则覆盖十、总结HashMap 核心就是一句话数组做主存哈希定位置链表解冲突红黑树提性能扩容保效率。理解它的哈希算法、下标定位、put/get 流程、扩容规则与树化机制就能彻底掌握 HashMap 原理无论是日常开发还是面试都能轻松应对。

更多文章