条件
- 扩容 resize( ) 时,红黑树拆分成的 树的结点数小于等于临界值6个,则退化成链表。
- 移除元素 remove( ) 时,在removeTreeNode( ) 方法会检查红黑树是否满足退化条件,与结点数无关。如果红黑树根 root 为空,或者 root 的左子树/右子树为空,root.left.left 根的左子树的左子树为空,都会发生红黑树退化成链表。
扩容 resize( ) 的源码分析
- 扩容时如果是红黑树结构会执行红黑树的 split( ) 方法
- split 方法中会初始化生成 loHead 和 hiHead 两个红黑树的头结点(之后会用 low 和 high 表示)
- lc 和 hc 分别为 low 和 high 的元素个数,初始化为0
- 把红黑树中的结点依次添加到 low 和 high 两颗红黑树中,依靠 (e.hash & bit) == 0 的位运算来判断属于哪颗树,bit是传过来的旧数组下标。每颗树元素的增加都会使对应的 lc 或 hc 自增1。
- 生成完 low 和 high 两颗红黑树后,如果对应的元素个数 lc,hc 小于等于6,退化成链表,否则维持红黑树形态。
- low树插入到新数组 tab[index] 的位置上,index是当前红黑树所在旧数组坐标;high树插入到新数组 tab[index + bit] 的位置上,bit是旧数组长度。
//退化链表的临界值
static final int UNTREEIFY_THRESHOLD = 6;
//1、扩容时如果是红黑树结构会执行split方法
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
//生成 low 和 high 两个红黑树
TreeNode<K,V> loHead = null, loTail = null;
TreeNode<K,V> hiHead = null, hiTail = null;
//lc是low树的元素个数,hc是high数的。
int lc = 0, hc = 0;
//把红黑树中的结点依次添加到 low 和 high 两颗红黑树中
//还是依靠 (e.hash & bit) == 0 的位运算来判断属于哪颗树,bit是传过来的旧数组下标
for (TreeNode<K,V> e = b, next; e != null; e = next) {
......
if ((e.hash & bit) == 0) {
//添加到 loHead
......
++lc;
}
else {
//添加到 hiHead
......
++hc;
}
}
if (loHead != null) {
//如果low树的元素个数小于等于6,退化成链表
//并插入到新数组 tab[index] 的位置上,index是当前红黑树所在旧数组坐标
if (lc <= UNTREEIFY_THRESHOLD)
tab[index] = loHead.untreeify(map);
else {
tab[index] = loHead;
if (hiHead != null) // (else is already treeified)
loHead.treeify(tab);
}
}
if (hiHead != null) {
//如果high树的元素个数小于等于6,退化成链表
//并插入到新数组 tab[index + bit] 的位置上,index是当前红黑树所在旧数组坐标,bit是旧数组长度
if (hc <= UNTREEIFY_THRESHOLD)
tab[index + bit] = hiHead.untreeify(map);
else {
tab[index + bit] = hiHead;
if (loHead != null)
hiHead.treeify(tab);
}
}
}
移除元素 remove( ) 时的源码
- 在 remove( ) 时如果是红黑树则执行 removeTreeNode( ) 方法 。
- 在 removeTreeNode( )的方法中,满足一定条件后会退化成链表,如果红黑树根 root 为空,或者 root 的左子树/右子树为空,root.left.left 根的左子树的左子树为空,都会发生红黑树退化成链表。
//remove时
//在removeTreeNode()的方法中,满足一定条件后会退化成链表
//条件中的movable是remove()方法传进来的true,ctrl+f没有发现哪里有做更改
//如果红黑树根root为空,或者root的左子树/右子树为空,root.left.left根的左子树的左子树为空
//这几种情况都会发生红黑树退化成链表
if (root == null
|| (movable
&& (root.right == null
|| (rl = root.left) == null
|| rl.left == null))) {
tab[index] = first.untreeify(map); // too small
return;
}
HashMap知识点总结(附源码分析链接)