//红黑树转回链表的阈值
static final int UNTREEIFY_THRESHOLD = 6;
/** 这个方法在HashMap进行扩容时会调用到: ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
* @param map 代表要扩容的HashMap
* @param tab 代表新创建的数组,用来存放旧数组迁移的数据
* @param index 代表旧数组的索引
* @param bit 代表旧数组的长度,需要配合使用来做按位与运算
*/
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
//做个赋值,因为这里是((TreeNode<K,V>)e)这个对象调用split()方法,所以this就是指(TreeNode<K,V>)e对象,所以才能类型对应赋值
TreeNode<K,V> b = this;
//设置低位首节点和低位尾节点
TreeNode<K,V> loHead = null, loTail = null;
//设置高位首节点和高位尾节点
TreeNode<K,V> hiHead = null, hiTail = null;
//定义两个变量lc和hc,初始值为0,后面比较要用,他们的大小决定了红黑树是否要转回链表
int lc = 0, hc = 0;
//这个for循环就是对从e节点开始对整个红黑树做遍历,如果对这循环赋值略有不懂,可以参考这篇模仿的博客@1
for (TreeNode<K,V> e = b, next; e != null; e = next) {
//取e的下一节点赋值给next遍历
next = (TreeNode<K,V>)e.next;
//取好e的下一节点后,把它赋值为空,方便GC回收
e.next = null;
//以下的操作就是做个按位与运算,按照结果拉出两条链表,具体的操作可以参考这篇博客@2
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;
}
}
//如果低位链表首节点不为null,说明有这个链表存在
if (loHead != null) {
//如果链表下的元素小于等于6
if (lc <= UNTREEIFY_THRESHOLD)
//那就从红黑树转链表了,低位链表,迁移到新数组中下标不变,还是等于原数组到下标
tab[index] = loHead.untreeify(map);
else {
//低位链表,迁移到新数组中下标不变,还是等于原数组到下标,把低位链表整个拉到这个下标下,做个赋值
tab[index] = loHead;
//如果高位首节点不为空,说明原来的红黑树已经被拆分成两个链表了
if (hiHead != null)
//那么就需要构建新的红黑树了
loHead.treeify(tab);
}
}
//如果高位链表首节点不为null,说明有这个链表存在
if (hiHead != null) {
//如果链表下的元素小于等于6
if (hc <= UNTREEIFY_THRESHOLD)
//那就从红黑树转链表了,高位链表,迁移到新数组中的下标=【旧数组+旧数组长度】
tab[index + bit] = hiHead.untreeify(map);
else {
//高位链表,迁移到新数组中的下标=【旧数组+旧数组长度】,把高位链表整个拉到这个新下标下,做赋值
tab[index + bit] = hiHead;
////如果低位首节点不为空,说明原来的红黑树已经被拆分成两个链表了
if (loHead != null)
//那么就需要构建新的红黑树了
hiHead.treeify(tab);
}
}
}
博客@1:模仿HashMap-split()方法中的for循环,方便理解
博客@2:关于按位与运算为什么能根据高低位拆分出两条链表,可以参考博客:HashMap的扩容机制(JDK1.8)