/** * tree桶方法. * 通常用做桶结构变动后,将桶中过长的链表转换为红黑树 */ final void treeifyBin(Node<K,V>[] tab, int hash) { // n - 表明参数tab长度 // index - tab中表示hash的下标 // hash - 待处理的链表节点hash // e - 目标节点 int n, index; Node<K,V> e; // 判断tab是否为空或tab长度MIN_TREEIFY_CAPACITY=64 // 也就是说,在桶中单个链表长度可能已经达到要求(如putVal中的binCount >= TREEIFY_THRESHOLD - 1),可是桶容量未达标时,也不会进行tree化 if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) // 表是空的或表容量小于MIN_TREEIFY_CAPACITY // 重置大小 resize(); // 能够tree化,检查链表节点是否存在 else if ((e = tab[index = (n - 1) & hash]) != null) { // 链表节点存在 // 树节点头与尾 TreeNode<K,V> hd = null, tl = null; // 已经有第一个目标,直接do while do { // 构造一个TreeNode.(这里没有额外逻辑,仅仅是使用当前的e建立了TreeNode) // 注意,这里的Tree继承自LinkedHashMap.Entry,内部包含了before与after的双向链表.可是TreeNode又自行实现了双向链表prev与next,并无使用前者的数据结构 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) // 调用TreeNode的treeify组装红黑树 hd.treeify(tab); } } /** * 组装红黑树 */ final void treeify(Node<K,V>[] tab) { // 根节点(黑色节点) TreeNode<K,V> root = null; // 进行迭代.(当前this做用域位于TreeNode实例) // x表示当前遍历中的节点 for (TreeNode<K,V> x = this, next; x != null; x = next) { // 缓存next next = (TreeNode<K,V>)x.next; // 保证当前节点左右节点为null x.left = x.right = null; // 判断是否存在根节点 if (root == null) { // 不存在 // 跟节点没有父级.因此设置为null x.parent = null; // 红黑树中,根节点是黑色的 x.red = false; // 保存到局部变量 root = x; } else { // 跟节点已确认 // 缓存key K k = x.key; // 缓存hash int h = x.hash; // key类型 Class<?> kc = null; // -------------------- 对跟节点进行遍历,查找插入位置 -------------------- // p是插入节点的父节点 for (TreeNode<K,V> p = root;;) { // dir - 用来表达左右. // ph - 父节点hash int dir, ph; // 父节点key K pk = p.key; // -------------------- 判断插入到左仍是右节点 -------------------- // 初始化父节点hash // 判断父节点hash是否大于当前节点hash if ((ph = p.hash) > h) // dir = -1 插入节点在父节点左侧 dir = -1; // 判断父节点hash是否小于当前节点hash else if (ph < h) // dir = 1 插入节点在父节点右侧 dir = 1; // 父节点hash等于当前节点hash,进行额外的处理 // 这里使用了基于Class的一些处理办法,最终保证了dir的正确值(不为0) TODO 待补充 else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) dir = tieBreakOrder(k, pk); // -------------------- 获取左或右节点并进行操做 -------------------- // 缓存插入节点的父节点 TreeNode<K,V> xp = p; // 使用dir获取父节点对应的左或右节点,而且检查这个节点是否为null.不为null时,进入下一次循环 if ((p = (dir <= 0) ? p.left : p.right) == null) { // 父节点左或右节点为null // 设置父级节点 x.parent = xp; // 再次判断左右 if (dir <= 0) // 将父节点的左子节点复制为当前节点 xp.left = x; else // 将父节点的右子节点复制为当前节点 xp.right = x; // 进行平衡 root = balanceInsertion(root, x); // 退出查找插入位置的循环,进行下一个元素的插入 break; } } } } // 由于在进行旋转操做时,可能会修改根节点到其余节点.致使桶中的直接节点为分支节点,因此须要进行修正 moveRootToFront(tab, root); }