put方法流程追踪
1、put
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
进入resize方法
2、resize
图1
新的阈值
创建数组,赋值给table属性
图2
回到put方法,根据计算获取数组下标位置,并从table数组中取出Node节点
如果不存在则创建新的节点对象
图3
第一次resize是进行了table的初始化赋值,此时进入resize真正进行扩容(接图2)
低位的则放入新数组的下标位置等于老的下标位置,高位则放入下标位置+老的容量
3、treeifyBin(接图3)
当Node链表长度达到了树化阈值,时,触发treeifyBin方法
截至当前,主要将链表中每个节点拿出来进行转换成TreeNode类型
重点关注treeify方法
final void treeify(Node<K,V>[] tab) {
TreeNode<K,V> root = null;
//this为调用者,此时为hd即TreeNode头节点
for (TreeNode<K,V> x = this, next; x != null; x = next) {
//获取头节点的下一个节点
next = (TreeNode<K,V>)x.next;
//赋值头节点的左右child为null
x.left = x.right = null;
if (root == null) {
x.parent = null;
x.red = false;
//将头节点赋值给root
root = x;
}
else {
//此时x为头节点的next节点,获取其key值
K k = x.key;
//获取节点的hash值
int h = x.hash;
Class<?> kc = null;
for (TreeNode<K,V> p = root;;) {
//此时p为树的根节点,
int dir, ph;
K pk = p.key;
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
TreeNode<K,V> xp = p;
//hash比较大小,小的放左边,大的放右边
//获取头节点的左节点/右节点,并重新赋值给p
//(此时为根节点的下一级节点)
//如果不为null则继续循环
if ((p = (dir <= 0) ? p.left : p.right) == null) {
//将当前xp赋值给x的父级节点属性(x为要处理的TreeNode)
x.parent = xp;
if (dir <= 0)
//双向绑定
xp.left = x;
else
//双向绑定
xp.right = x;
root = balanceInsertion(root, x);
break;
}
}
}
}
moveRootToFront(tab, root);
}