0
点赞
收藏
分享

微信扫一扫

jdk1.8HashMap扩容后链表拆分过程解析

源码预览

jdk1.8HashMap扩容后链表拆分过程解析_数组

拆分思路

如果e 元素是链表类型,则需要遍历链表,将其一拆为二

故定义了low 、high两个链表的头尾指针。

Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;

将e的hash码与原数组容量进行按位与,如果结果为零,则加入低位链表

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);

遍历完成之后,低位链表位置不变,还是在原来的位置上,即 位置 j 

if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}

高位链表则需要搬家,搬到原来位置加上原数组容量的位置上,如果原理位置为5,原容量为16,扩容后则位置为5+16 = 21.

if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}

逐行解析

table = newTab; //扩容后的新数组
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {// 遍历原数组
HashMap.Node<K,V> e;
if ((e = oldTab[j]) != null) {// 原元素不为null
oldTab[j] = null;
if (e.next == null)// 如果next为null,说明是单独的元素
newTab[e.hash & (newCap - 1)] = e;//直接放在新数组 计算后相应的位置即可
else if (e instanceof HashMap.TreeNode)// 如果该元素时树节点,按树的流程走
((HashMap.TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order 否则,那就是链表,是链表就要一分为二
HashMap.Node<K,V> loHead = null, loTail = null;// 定义一个低位链表(low)
HashMap.Node<K,V> hiHead = null, hiTail = null;// 一个高位链表(high)
HashMap.Node<K,V> next;
do {// 循环变量链表
next = e.next;
if ((e.hash & oldCap) == 0) {// 如果 & 运算结果为0 则加入低位链表
if (loTail == null)//插入第一个元素
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {// 如果 & 运算结果不为0 则加入高位链表
if (hiTail == null)//插入第一个元素
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);//直至遍历完链表
if (loTail != null) {
loTail.next = null;// 将尾节点置为null。
newTab[j] = loHead;//将低位链表的头节点指向 原来元素所在位置
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;//将高位位链表的头节点指向 原来元素所在位置+原数组容量的位置
}
}
}
}
}
return newTab;//返回扩容后的数组


举报

相关推荐

0 条评论