【源码解析】HashMap 核心设计与源码速览 (JDK 8+)
前言
HashMap
几乎是 Java 面试和开发中的“必考题”和“必备品”。它提供了高效的键值对存储和查找能力(平均时间复杂度 O(1))。理解其内部实现原理,不仅有助于我们写出更优的代码,也能在面试中脱颖而出。本文旨在快速梳理 HashMap
(以 JDK 8+ 为基础) 的核心设计和源码要点,助你快速入门。
通过本文,你将快速理解:
HashMap
的基本数据结构(数组 + 链表/红黑树)。put
和get
操作的核心流程。- 哈希冲突是如何发生的,以及如何解决(链地址法、树化)。
- 动态扩容(resize)的触发时机和过程。
核心数据结构:数组 + 链表 / 红黑树
HashMap
内部维护了一个 Node<K,V>[] table
数组,这是其主体结构,也常被称为“桶”(bucket)数组。每个桶(数组元素)可以存放一个 Node
节点,或者是一条 Node
组成的链表,或者是一棵红黑树(TreeNode
)。

HashMap 内部结构示意图 (JDK 8+)
transient Node<K,V>[] table
: 存储数据的桶数组,长度总是 2 的幂次方。transient Set<Map.Entry<K,V>> entrySet
: 缓存的 entry 集合。transient int size
:HashMap
中存储的键值对数量。transient int modCount
: 修改次数,用于迭代时的快速失败机制。int threshold
: 扩容阈值,当size
超过这个值时触发扩容。threshold = capacity * loadFactor
。final float loadFactor
: 负载因子,默认为 0.75f。控制数组的填充程度。static final int TREEIFY_THRESHOLD = 8
: 链表转红黑树的阈值。当一个桶中的链表长度达到 8 时,并且table
的容量capacity
大于等于MIN_TREEIFY_CAPACITY
(64) 时,链表会转化为红黑树。static final int UNTREEIFY_THRESHOLD = 6
: 红黑树转链表的阈值。当扩容时,如果一个桶中的节点数减少到 6,红黑树会退化回链表。static final int MIN_TREEIFY_CAPACITY = 64
: 允许链表树化的最小table
容量。如果容量小于此值,即使链表长度达到 8,也只会进行扩容,而不会树化。
put(K key, V value)
核心流程
put
方法是 HashMap
最核心的操作之一。