HashMap 作为 Java 集合框架中最核心、最常用的键值对存储容器,几乎是后端开发中无处不在的工具类。无论是业务数据缓存、对象映射、快速查找,还是框架底层实现,HashMap 都承担着关键角色。同时,它也是 Java 面试中必问、必考、必深挖的知识点,从基础结构、哈希算法、冲突解决,到扩容机制、线程安全问题,再到 JDK 1.8 的红黑树优化,都是考察开发者基本功的核心内容。
本文将从基础定义、底层数据结构、核心源码流程、扩容机制、JDK 版本差异、高频面试题六个维度,带你彻底吃透 HashMap。
一、HashMap 基础认知
1.1 什么是 HashMap?
HashMap 是 Java 中基于哈希表实现的键值对(key-value)存储集合,继承自 AbstractMap,实现了 Map 接口。它的核心设计目标是极高的存取效率,理想情况下,put(存)和 get(取)操作的时间复杂度都能达到 O(1)。
1.2 HashMap 的核心特性
- key 唯一,value 可重复:key 依靠
hashCode()和equals()保证唯一性,value 可以重复存储。 - 允许 null 值:key 最多允许 1 个 null,value 允许多个 null。
- 无序性:存储顺序和插入顺序无关,且随着扩容,元素位置会发生变化。
- 非线程安全:多线程环境下使用会出现数据覆盖、死循环等问题,并发场景推荐使用
ConcurrentHashMap。 - 底层动态扩容:通过扩容机制避免哈希冲突过多,保证存取性能。
二、HashMap 底层数据结构详解
HashMap 的底层结构,在 JDK 1.7 和 JDK 1.8 中发生了重大优化,这也是理解 HashMap 的关键。
2.1 JDK 1.7:数组 + 链表
JDK 1.7 的 HashMap 采用数组 + 单向链表的结构:
- 数组(哈希桶):是 HashMap 的主体,用于快速定位元素,每个下标位置称为一个'桶'。
- 链表:用于解决哈希冲突,当多个 key 计算出相同数组下标时,以链表形式挂载在对应下标下。
缺陷:当哈希冲突严重时,链表会变得很长,查找效率会从 O(1) 退化到 O(n),严重影响性能。
2.2 JDK 1.8:数组 + 链表 + 红黑树
JDK 1.8 对底层结构做了里程碑式优化,引入红黑树:
- 当链表长度达到 8,且数组长度达到 64 时,链表会树化转为红黑树,将查找效率从 O(n) 提升到 O(log n)。
- 当红黑树节点数量减少到 6 时,红黑树会退化为链表,节省内存空间。
最终结构:数组是主干,链表处理普通冲突,红黑树处理极端冲突。
三、HashMap 核心参数与默认值
HashMap 的性能和行为,由以下几个核心参数控制:
| 参数 | 含义 | 默认值 | 作用 |
|---|---|---|---|
| 初始容量 | 数组的初始长度 | 16 | 必须是 2 的 n 次方,保证哈希下标计算均匀 |
| 加载因子 | 数组的填充阈值 | 0.75 | 平衡空间占用和哈希冲突概率的核心参数 |
| 扩容阈值 | 触发扩容的元素数量 | 容量 × 加载因子 |

