final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;//n是数组长度,e是hash值和数组长度计算后,得到链表的首节点
/** 如果数组为空或者数组长度小于树结构化的最小限制
* MIN_TREEIFY_CAPACITY 默认值64,对于这个值可以理解为:如果元素数组长度小于这个值,没有必要去进行结构转换
* 当一个数组位置上集中了多个键值对,那是因为这些key的hash值和数组长度取模之后结果相同。(并不是因为这些key的hash值相同)
* 因为hash值相同的概率不高,所以可以通过扩容的方式,来使得最终这些key的hash值在和新的数组长度取模之后,拆分到多个数组位置上。
*/
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
// 如果元素数组长度已经大于等于了 MIN_TREEIFY_CAPACITY,那么就有必要进行结构转换了
// 根据hash值和数组长度进行取模运算后,得到链表的首节点
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;//hd是树首节点,tl是树尾节点
do {
TreeNode<K,V> p = replacementTreeNode(e, null);//节点转换为树节点
if (tl == null)//如果树尾节点为空说明没有根节点
hd = p;//附值给首节点,树的根节点
else {// 尾节点不为空,以下两行是一个双向链表结构
p.prev = tl;//双链表,prev指向前一个节点,尾节点
tl.next = p;//next指向下一个节点,当前节点
}
tl = p;// 把当前节点设为尾节点
} while ((e = e.next) != null);
// 到目前为止 也只是把Node对象转换成了TreeNode对象,把单向链表转换成了双向链表
// 把转换后的双向链表,替换原来位置上的单向链表
if ((tab[index] = hd) != null)
hd.treeify(tab);//转换成红黑树
}
}
参考老艮头的JDK8:HashMap源码解析:treeifyBin方法https://blog.csdn.net/weixin_42340670/article/details/80503863