详解HashMap集合( 九 )

next){return new Node<>(hash, key, value, next);}注意第四个参数next是null , 因为当前元素插入到链表末尾了 , 那么下一个节点肯定是null2)这种添加方式也满足链表数据结构的特点 , 每次向后添加新的元素*/p.next = newNode(hash, key, value, null);/*1)节点添加完成之后判断此时节点个数是否大于TREEIFY_THRESHOLD临界值8 , 如果大于则将链表转换为红黑树2)int binCount = 0 :表示for循环的初始化值 。 从0开始计数 。 记录着遍历节点的个数 。 值是0表示第一个节点 , 1表示第二个节点 。。。。 7表示第八个节点 , 加上数组中的的一个元素 , 元素个数是9TREEIFY_THRESHOLD - 1 --》8 - 1 ---》7如果binCount的值是7(加上数组中的的一个元素 , 元素个数是9)TREEIFY_THRESHOLD - 1也是7 , 此时转换红黑树*/if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st//转换为红黑树treeifyBin(tab, hash);// 跳出循环break;}/*执行到这里说明e = p.next 不是null , 不是最后一个元素 。 继续判断链表中结点的key值与插入的元素的key值是否相等*/if (e.hash == hash/*说明新添加的元素和当前节点不相等 , 继续查找下一个节点 。用于遍历桶中的链表 , 与前面的e = p.next组合 , 可以遍历链表*/p = e;}}/*表示在桶中找到key值、hash值与插入元素相等的结点也就是说通过上面的操作找到了重复的键 , 所以这里就是把该键的值变为新的值 , 并返回旧值这里完成了put方法的修改功能*/if (e != null) {// 记录e的valueV oldValue = http://kandian.youth.cn/index/e.value;// onlyIfAbsent为false或者旧值为nullif (!onlyIfAbsent || oldValue == null)//用新值替换旧值//e.value 表示旧值value表示新值e.value = value;// 访问后回调afterNodeAccess(e);// 返回旧值return oldValue;}}//修改记录次数++modCount;// 判断实际大小是否大于threshold阈值 , 如果超过则扩容if (++size> threshold)resize();// 插入后回调afterNodeInsertion(evict);return null;} 4.3.2将链表转换为红黑树的treeifyBin方法节点添加完成之后判断此时节点个数是否大于TREEIFY_THRESHOLD临界值8 , 如果大于则将链表转换为红黑树 , 转换红黑树的方法 treeifyBin , 整体代码如下:
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st//转换为红黑树 tab表示数组名hash表示哈希值treeifyBin(tab, hash);treeifyBin方法如下所示:
/*** Replaces all linked nodes in bin at index for given hash unless* table is too small, in which case resizes instead.替换指定哈希表的索引处桶中的所有链接节点 , 除非表太小 , 否则将修改大小 。Node[] tab = tab 数组名int hash = hash表示哈希值*/final void treeifyBin(Node[] tab, int hash) {int n, index; Node e;/*如果当前数组为空或者数组的长度小于进行树形化的阈值(MIN_TREEIFY_CAPACITY = 64),就去扩容 。 而不是将节点变为红黑树 。目的:如果数组很小 , 那么转换红黑树 , 然后遍历效率要低一些 。 这时进行扩容 , 那么重新计算哈希值, 链表长度有可能就变短了 , 数据会放到数组中 , 这样相对来说效率高一些 。*/if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)//扩容方法resize();else if ((e = tab[index = (n - 1)do {//新创建一个树的节点 , 内容和当前链表节点e一致TreeNode p = replacementTreeNode(e, null);if (tl == null)//将新创键的p节点赋值给红黑树的头结点hd = p;else {/*p.prev = tl:将上一个节点p赋值给现在的p的前一个节点tl.next = p;将现在节点p作为树的尾结点的下一个节点*/p.prev = tl;tl.next = p;}tl = p;/*e = e.next 将当前节点的下一个节点赋值给e,如果下一个节点不等于null则回到上面继续取出链表中节点转换为红黑树*/} while ((e = e.next) != null);/*让桶中的第一个元素即数组中的元素指向新建的红黑树的节点 , 以后这个桶里的元素就是红黑树而不是链表数据结构了*/if ((tab[index] = hd) != null)hd.treeify(tab);}}


推荐阅读