1、TreeNode的静态方法是否对数据结构进行树化-treeify()
这里有几个参数必须区别开来
/**
* 桶的链表还原阈值:即 红黑树转为链表的阈值,当在扩容(resize())时(此时HashMap的数据存储位置会重新计算),
* 在重新计算存储位置后,当原有的红黑树内数量 < 6时,则将 红黑树转换成链表
*/
private static final int UNTREEIFY_THRESHOLD = 6;
/**
* 桶的树化阈值:即 链表转成红黑树的阈值,在存储数据时,当链表长度 > 该值时,则将链表转换成红黑树
*/
private static final int TREEIFY_THRESHOLD = 8;
/**
* 我们可以将存放元素的数组 transient Node<K,V>[] table 理解为一个装与萨努的桶数组
* MIN_TREEIFY_CAPACITY 默认值64(至少4倍桶的树化阈值TREEIFY_THRESHOLD,避免调整大小与树化阈值之间发生冲突),对于这个值可以理解为:当桶的数量小于这个值的时候,没有必要去进行结构转换,
* 我们先对桶进行扩容,然后对每个桶的元素进行分散化。详见扩容方法resize().
* 当一个数组位置上集中了多个键值对,那是因为这些key的hash值和数组长度取模之后结果相同。(并不是因为这些key的hash值相同)
* 因为hash值相同的概率不高,所以可以通过扩容的方式,来使得最终这些key的hash值在和新的数组长度取模之后,拆分到多个数组位置上。
*/
private static final int MIN_TREEIFY_CAPACITY = 64;
/**
* @param tab 存放Map的数组元素
* @param hash 链表key的hash值
* @return void
* @Author muyi
* @Date 10:25 2020/8/3
*/
final void treeifyBin(HashMap.Node<K, V>[] tab, int hash) {
int n, index;
HashMap.Node<K, V> e;
// 当桶的数组为空或者桶的数量小于64时,是不允许树化的,先对桶进行扩容,扩容完成了,如果链表的长度还是大于等于8,那么必须树化,
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
// 扩容方法,详见分析文章4
resize();
// 将当前节点指向链表位置的头节点元素
else if ((e = tab[index = (n - 1) & hash]) != null) {
// hd-链表头节点,tl-链表尾节点,遍历链表,将链表中的所有节点替换成树形节点
HashMap.TreeNode<K, V> hd = null, tl = null;
do {
// 根据链表节点生成树形节点,
HashMap.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)
hd.treeify(tab);
}
}
2、树化方法treeifyBin(),它是HashMap的一个final方法。
/**
* 将双向链表进行树化
*
* @param tab 双向链表
* @return void
* @Author muyi
* @Date 14:09 2020/7/30
*/
final void treeify(HashMap.Node<K, V>[] tab) {
// 存放数据的红黑树根节点,
HashMap.TreeNode<K, V> root = null;
// 遍历链表元素,this-当前节点(这是树形节点类的静态方法,this指的就是当前节点),next-下一个节点
for (HashMap.TreeNode<K, V> x = this, next; x != null; x = next) {
next = (HashMap.TreeNode<K, V>) x.next;
x.left = x.right = null;
// 如果root节点为空,说明当前添加的元素位于root位置,
if (root == null) {
x.parent = null;
x.red = false;
root = x;
} else {
K k = x.key;
int h = x.hash;
Class<?> kc = null;
// 比较点的hash值
for (HashMap.TreeNode<K, V> p = root; ; ) {
int dir, ph;
K pk = p.key;
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
/**
* 如果两个hash值相等,两个条件取或值(如果继承了comparable接口就是,没继承的话就使用默认方法进行计算)
* 1、(kc == null && (kc = comparableClassFor(k)) == null):实现comparable接口的类为NULL
* 2、(dir = compareComparables(kc, k, pk)) == 0:
*/
else if ((kc == null && (kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
HashMap.TreeNode<K, V> xp = p;
// 如果当前节点的hash值较小,则置于左子树,反之,则置于右子树
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
// 平衡红黑树
root = balanceInsertion(root, x);
break;
}
}
}
}
// 将根节点移动到链表的头节点
moveRootToFront(tab, root);
}