接下来会从以下几个方面介绍 HashMap 源码相关知识:
1、HashMap 存储结构
2、HashMap 各常量、成员变量作用
3、HashMap 几种构造方法
4、HashMap put 及其相关方法
5、HashMap get 及其相关方法
6、HashMap remove 及其相关方法
7、HashMap 扩容方法 resize()
介绍方法时会包含方法实现相关细节。
先来看一下 HashMap 的继承图:

HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap 最多只允许一条记录的键为 null ,允许多条记录的值为 null 。HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections的synchronizedMap 方法使 HashMap 具有线程安全的能力,或者使用ConcurrentHashMap。
一、HashMap 存储结构
HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下图所示:

源码中具体实现如下:
[Java] 纯文本查看 复制代码
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
// Node<K,V> 类用来实现数组及链表的数据结构
static class Node<K,V> implements Map.Entry<K,V> {
final int hash; //保存节点的 hash 值
final K key; //保存节点的 key 值
V value; //保存节点的 value 值
Node<K,V> next; //指向链表结构下的当前节点的 next 节点,红黑树 TreeNode 节点中也有用到
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { }
public final V getValue() { }
public final String toString() { }
public final int hashCode() {
}
public final V setValue(V newValue) {
}
public final boolean equals(Object o) {
}
}
public class LinkedHashMap<K,V> {
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
}
// TreeNode<K,V> 继承 LinkedHashMap.Entry<K,V>,用来实现红黑树相关的存储结构
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // 存储当前节点的父节点
TreeNode<K,V> left; //存储当前节点的左孩子
TreeNode<K,V> right; //存储当前节点的右孩子
TreeNode<K,V> prev; // 存储当前节点的前一个节点
boolean red; // 存储当前节点的颜色(红、黑)
TreeNode(int hash, K key, V val, Node<K,V> next) {
super(hash, key, val, next);
}
}
|
二、HashMap 各常量、成员变量作用
[Java] 纯文本查看 复制代码
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
//创建 HashMap 时未指定初始容量情况下的默认容量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
//HashMap 的最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
//HashMap 默认的装载因子,当 HashMap 中元素数量超过 容量*装载因子 时,进行 resize() 操作
static final float DEFAULT_LOAD_FACTOR = 0.75f;
//用来确定何时将解决 hash 冲突的链表转变为红黑树
static final int TREEIFY_THRESHOLD = 8;
// 用来确定何时将解决 hash 冲突的红黑树转变为链表
static final int UNTREEIFY_THRESHOLD = 6;
/* 当需要将解决 hash 冲突的链表转变为红黑树时,需要判断下此时数组容量,若是由于数组容量太小(小于 MIN_TREEIFY_CAPACITY )导致的 hash冲突太多,则不进行链表转变为红黑树操作,转为利用 resize() 函数对 hashMap 扩容 */
static final int MIN_TREEIFY_CAPACITY = 64;
|
[Java] 纯文本查看 复制代码
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
//保存Node<K,V>节点的数组
transient Node<K,V>[] table;
//由 hashMap 中 Node<K,V> 节点构成的 set
transient Set<Map.Entry<K,V>> entrySet;
//记录 hashMap 当前存储的元素的数量
transient int size;
//记录 hashMap 发生结构性变化的次数(注意 value 的覆盖不属于结构性变化)
transient int modCount;
//threshold的值应等于 table.length * loadFactor, size 超过这个值时进行 resize()扩容
int threshold;
//记录 hashMap 装载因子
final float loadFactor;
|
三、HashMap 几种构造方法
[Java] 纯文本查看 复制代码
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|

本文深入剖析HashMap在JDK1.8中的实现,涵盖存储结构、常量成员、构造方法、put/get/remove操作及resize()方法。HashMap基于数组+链表+红黑树,提供快速访问但非线程安全。扩容时,元素通过rehash分布到新槽,解决冲突并保持高效性能。
最低0.47元/天 解锁文章
394

被折叠的 条评论
为什么被折叠?



