/** * 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); }