一、概览
HashMap的某个桶位如果存储的是单向列表,当向这个桶位继续插入一个元素的时候,这个桶位元素的数量超过
8时,单项列表会转化为红黑树(同时是一个双向列表,jdk1.8之后),且会先转化为双向列表:
二、转化过程
1,运行如下程序,使map底层数组的某个桶位的单向列表”开始“转化为红黑树
按道理,当map-put的元素超过 8*100 = 800时才会扩容数组,所以,当map.put(65, "65")时,table[1]的位置将会是:
此时,table[1]的元素数量(9个)超过8(TREEIFY_THRESHOLD),这个单向列表会被转化为红黑树,但是受
这个数字的影响,数组的长度(现在为8)只有扩容到64之后,才会将单向列表会被转化为红黑树;扩容的过程:参考(参考http:还没写好)。
当map.put(513, "513")时,table[1]的位置将会是:
此时,table[1]的元素数量(9个)超过8(TREEIFY_THRESHOLD),这个单向列表”将会“被转化为红黑树。
2,单向列表转化为红黑树
先转化为双向链表,双向链表转化为红黑树,参考:http:还没有写好;
jdk1.8 - HashMap源代码如下红框所示:
e:tab[1],是一条单向链表,如上面数组的那个示意图,节点都是Node类型,随着单向列表不断的递进,指向的当前单向列表的节点;
hd:head?头部节点,双向列表的头部节点,节点是TreeNode类型;
tl:tail?尾部节点,双向列表的尾部节点,节点是TreeNode类型;
p:e当前指向的单向列表的节点转化为TreeNode类型后的节点;
2.1,Node和TreeNode的联系与区别
Node:
TreeNode:,
TreeNode是Node的子类,也就是说TreeNode含有Node的所有属性;
Node是一个含有next属性的单向列表,TreeNode是一个含有next(继承自Node)、prev属性的双向链表,同时TreeNode还是一个含有left、right、parent属性的二叉树,同时TreeNode还是一个含有boolean red属性的红黑树(在二叉树的基础上)。
2.2,单向列表开始转化为双向链表
p的来源:
1,第一次循环
2,第二次循环
3,第三次循环
4,以此类推
总结下来,就是:
A、让单向列表递进,使用局部变量(中间变量)e指向递进过程中的某个节点;
B、使用中间变量p,根据步骤A中的e构造出一个双向链表的节点(当前还没有挂到双向列表上);
C、如果双向链表的尾部为空,即双向链表没有任何节点,则让步骤B中的p既作为头也作为尾;
如果双向链表的尾部不为空:则需要将步骤B中的p挂到双向列表的尾部;
D、最后,由于双向列表的尾部发生了变化,需要将tl指向新的尾部节点。