0%

HashMap & LinkedHashMap 源码

HashMap & LinkedHashMap 是日常开发中用的最多的两个Map子类, LinkedHashMap是HashMap子类, HashMap在实现底层存储的实现中,有一些列很有意思的操作,有必要了解一下.

HashMap

这里的源码环境是JDK 1.8.

HashMap

构造函数

HashMap 提供了4个构造函数,这里我只列出了3个, HashMap构造可以设置初始化容量,增长因子;

构造方法中tableSizeFor(int cap)方法, 很巧妙的计算 32位 int 类型 cap 其最接近cap值的 2的最高指数;

比如:

cap = 33, 那么计算结果就是 2^5 = 32;

cap = 69, 那么计算结果就是 2^6 = 64;

这个降幂的计算关系到后面扩容, 这些0,1 果然是高级程序员的好朋友呀!

我们下面讨论的都是建立在默认配置的条件下:

  • capacity = DEFAULT_INITIAL_CAPACITY = 16

  • threshold = 0.75 * 16 = 12

    这两个值有必要记录一下;

1
2
3
4
5
6
7
8
9
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
     // 默认初始化容量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

//最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;

//默认增长因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;

// 存储数据的数组
transient Node<K,V>[] table;

public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
// 计算扩容阈值
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

存储实现

下面我们来看存储的方法,从 put(K key, V value) 方法中,查看HashMap 的是通过什么数据结构来实现存储的.

1
2
3
4
5
6
7
8
9
10
11

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

// 计算hash值
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

下面就是put方法的重点内容了.

1
2
3
4
5
6
7
8
9
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

//链表对象
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
// 如果是空HashMap
if ((tab = table) == null || (n = tab.length) == 0)
// 初始化容器
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
// 如果 数组tab 位置没有存储值 ,给数组存值
tab[i] = newNode(hash, key, value, null);
else {
//如果 tab [ (n - 1) & hash] 位置有值了
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
// 要存的内容 和 现在有的值 一模一样
e = p;
// 如果 tab 位置取出来的是 一个 TreeNode
else if (p instanceof TreeNode)
// 将要存的值 存到这棵树上
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
// 其他( tab 中的链表 数量不足 )
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
// 将存值 存储在链表尾端
p.next = newNode(hash, key, value, null);
// 如果链表上子不算头结点的情况下 已经超过 7
// 因为头结点已经存在 所以 -1
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
// 将链表转换成 红黑树存储方式存储
treeifyBin(tab, hash);
break;
}
// 存值结束 跳出循环
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
//一个回调空方法,提供扩展用
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
// 如果容量达到 阈值 需要扩容
resize();
//一个回调空方法,提供扩展用
afterNodeInsertion(evict);
return null;
}

putVal 方法中我们可以看到, HashMap 底层维护了这一个数组, 这个数组的 index 数值内容有 key的hash 与 数组长度n 有关.

1
i = (n - 1) & hash

HashMap 利用 key 的hash值 经过与 n-1 与运算之后的来确定要存储在数组的那个位置.

采用这种的计算方式,当数据量多了,就一定存在着不同的key,经过计算之后 i 相同的情况, HashMap 巧妙的利用了这些方式实现了其底层的存储结构, 也就是你听说过的 Hash散链表.

HashMap 底层存储实现是一个变换过程, 根据存储数据的量,HashMap会变换存储的数据结构,来达到HashMap查询快,删除快的目的.

存储升级过程

数组 方式

HashMap 中的key & n-1 不存在与其他key 计算结果相同的条件下, HashMap 的存储结构只需要使用数组.

1
2
3
4
5
6
7
8
9
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
// 初始化
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
// 给数组赋值
tab[i] = newNode(hash, key, value, null);
else {
... //非 数组 方式
}
++modCount;
if (++size > threshold)
//扩容
resize();
return null;
}

// 扩容方法
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else {
// 初始化
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
// 扩容之后 按照新tab 的大小重新计算 并赋值
newTab[e.hash & (newCap - 1)] = e;
else { // preserve order
...
}
}
}
return newTab;
}

数组 + 单链表 方式

HashMap 中的key & n-1 存在与其他key 计算结果相同的条件下, 数组长度小于64.
HashMap 的存储结构就会使用到 数组 + 单链表.

1
2
3
4
5
6
7
8
9
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
// hash 计算完 tab对应的index 位置,已经存在一个节点
Node<K,V> e; K k;
// 如果key 相等(覆盖)
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
... // 红黑树的情况
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
// 添加在单链表的尾端
p.next = newNode(hash, key, value, null);
// 链表 原先是否已经达到 8 个(第9个 需要扩容)
// 因为头结点已经存在 所以 -1
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
// 如果 tab length 达到64 则转为红黑树, 如果没有 将数组 横向扩容,
treeifyBin(tab, hash);
break;
}
// 完成到尾部,结束循环
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}

//已经存在的key , 覆盖value 返回
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();

return null;
}



final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
//扩容
resize();
else if ((e = tab[index = (n - 1) & hash]) != null) {
// 红黑树逻辑
}
}

//扩容方法
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
// 将单链表拆分 为两个部分, 一部分存在原index ,一部分 存在新的index
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}

数组 + 单链表 + 红黑树 方式

HashMap 中的key & n-1 存在与其他key 计算结果相同的条件下, 数组长度小于64,且插入的数据前,其对应的单链表长度达到7, 在添加完数据到链表后,HashMap会将该单链转为红黑树.
因此HashMap 的存储结构就会使用到 数组 + 单链表 + 红黑树.

下面是完整的代码与注释

1
2
3
4
5
6
7
8
9
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//判断是否null 数组
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
//数组 index 没保存节点
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
// 如果是 要存的数据 已经在数组上
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 数组上存值 是 红黑树节点
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
// 遍历单链表
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
// 将数据添加在单链表尾部
p.next = newNode(hash, key, value, null);
// 添加之前 单链表上的节点数 已经达到 8
//因为头结点已经存在 所以 -1
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
// 转换(扩容/变换)
treeifyBin(tab, hash);
break;
}
// 如果链表上已经存在该key
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// 如果链表上已经存在该key, 将value 更新
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
// 扩展方法
afterNodeAccess(e);
return oldValue;
}
}
//操作数+1
++modCount;
// 容器内元素个数计算+1
if (++size > threshold)
//扩容
resize();
// 扩展方法
afterNodeInsertion(evict);
return null;
}


final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
// 长度小于64 或者 null 数组 , 达不到转红黑树条件
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
//满足红黑树条件
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
do {
// 将该单链表 转为红黑树
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)
//调整root 节点
hd.treeify(tab);
}
}


final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
// 数组扩容
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
// 数组扩容
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
// 数组初始化
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
// 数组初始化
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
// 数组上的节点 只是一个单节点
newTab[e.hash & (newCap - 1)] = e;
// 如果是红黑树
else if (e instanceof TreeNode)
// 红黑树 扩容 数据重新分配
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
// 单链表扩容 数据重新分配
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}

扩容

只要执行扩容,数组的长度就会变为原来的2倍, 数组中的节点,不管是单节点,单链表,还是红黑树根节点, 都需要重新计算存储数组的位置.来保证HashMap的平衡.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}

@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;

数组扩容

这个这里就直接跳过了, 重新计算下hash 与 新的数组长度,重新确认存储在tab中的位置;

map

单链表扩容

当HashMap 采用了数组和单链表数据结构存储, 但是数组长度不够64位,HashMap存储的元素达到扩容阈值的时候, 会执行横向的数组扩容,并将链表有规律的重新分配到新的数组中去.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

final Node<K,V>[] resize() {
// 执行有规律的扩容
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}

红黑树扩容

每次扩容,红黑树也需要重新调整,匀一部分去新的数组中去;

这里有一个 int UNTREEIFY_THRESHOLD = 6 ,如果元素个数重新分配之后 <= 6 , 转为单链表;

为什么UNTREEIFY_THRESHOLD 定义为6呢?

这里lc 和``hc 都是从0 开始的, 而且是已经有头结点的情况下;

如果个数 <=6 (链表中元素个数 不足 7,包含头) 还没有达到 8 ,这个链表可以至少在添加一个元素;

如果个数 >6 (链表中元素个数 为 7,包含头) 至少下达到 8 , 这个链表再添加一个元素,也将执行变换红黑树流程 ,为了下次可以直接添加, 所以提前转成红黑树.

可以看到 红黑树上元素 分配的过程和 单链表上元素分配的方法几乎一致;

1
2
3
4
5
6
7
8
9
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
49
50
51
52
53
54

final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
TreeNode<K,V> b = this;
// Relink into lo and hi lists, preserving order
TreeNode<K,V> loHead = null, loTail = null;
TreeNode<K,V> hiHead = null, hiTail = null;
int lc = 0, hc = 0;
for (TreeNode<K,V> e = b, next; e != null; e = next) {
next = (TreeNode<K,V>)e.next;
e.next = null;
if ((e.hash & bit) == 0) {
if ((e.prev = loTail) == null)
loHead = e;
else
loTail.next = e;
loTail = e;
++lc;
}
else {
if ((e.prev = hiTail) == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
++hc;
}
}

if (loHead != null) {
if (lc <= UNTREEIFY_THRESHOLD)
//如果数量小于6 转为单链表(没有算头结点)
tab[index] = loHead.untreeify(map);
else {
//红黑树
tab[index] = loHead;
if (hiHead != null) // (else is already treeified)
//红黑树调整逻辑
loHead.treeify(tab);
}
}
if (hiHead != null) {
if (hc <= UNTREEIFY_THRESHOLD)
//如果数量小于6 转为单链表(没有算头结点)
tab[index + bit] = hiHead.untreeify(map);
else {
//红黑树
tab[index + bit] = hiHead;
if (loHead != null)
//红黑树调整逻辑
hiHead.treeify(tab);
}
}
}

链表元素分配方法

map

这里假设 :

tab 长度为默认 16

阈值为 12

tab[ 0 ] 的计算规则

xxxx0000 & 00001111 = 00000000

按照源码中的扩容规则,xxxx0000 & 00010000 是否等于 0 ,可以分为两种情况:

xxx00000 & 00010000 = 00000000

xxx00000 维持原数组index位置.

扩容前 xxx00000 & 00001111 = 00000000

扩容后 xxx00000 & 00011111 = 00000000

xxx10000 存储位置改为 原数组index 0 + 16位置.

xxx10000 & 00010000 != 00010000

其他位置的元素可以用同样的方法推导, 图中有画出index = 0 , 1 的过程;

采用这种分配方法可以实现 HashMap的存储平衡.

LinkedHashMap

map继承关系

LinkedHashMap 继承了HashMap 底层实现几乎一致,也是数组和链表,红黑树的数据结构,只是 LinkedHashMap 用的链表是 双向链表;

1
2
3
4
5
6
7
8
9
10

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);
}
}
transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;
}