jdk1.8 hashmap.putTreeVal方法解析
阿新 • • 發佈:2018-12-13
final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab, int h, K k, V v) { Class<?> kc = null;//k的型別 boolean searched = false;//是否遍歷過樹了 TreeNode<K,V> root = (parent != null) ? root() : this;//樹的根節點 for (TreeNode<K,V> p = root;;) { int dir, ph; K pk;//dir樹的左右方向,ph當前節點的hash,pk當前節點的key值 if ((ph = p.hash) > h) dir = -1; else if (ph < h) dir = 1; else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; //根據當前節點key值、hash和傳進來要插入的key值、hash一般都能得到一個左或右方向 //或者當前節點key值、hash和傳進來要插入的key值、hash相等或equals //但是還有一種情況就是hash相等key不equals else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) { //走到這裡說明:指定key沒有實現comparable介面 //或者實現了comparable介面並且和當前節點的鍵物件比較之後相等 /**searched 標識是否已經對比過當前節點的左右子節點了 * 如果還沒有遍歷過,那麼就遞迴遍歷對比,看是否能夠得到那個鍵物件equals相等的節點 * 如果得到了鍵的equals相等的的節點就返回 * 如果還是沒有鍵的equals相等的節點,那說明應該建立一個新節點了 * find(h, k, kc)遞迴、while遍歷ch的所有節點直到找到與k equals的節點否則就返回空 */ if (!searched) { TreeNode<K,V> q, ch; searched = true; if (((ch = p.left) != null && (q = ch.find(h, k, kc)) != null) || ((ch = p.right) != null && (q = ch.find(h, k, kc)) != null)) return q; } // 走到這裡就說明,遍歷了所有子節點也沒有找到和當前鍵equals相等的節點 dir = tieBreakOrder(k, pk);//把兩個key的object的hashcode()方法生成的hashcode比較決定方向 } TreeNode<K,V> xp = p; // 定義xp指向當前節點 /* * 如果dir小於等於0,那麼看當前節點的左節點是否為空,如果為空,就可以把要新增的元素作為當前節點的左節點,如果不為空,還需要下一輪繼續比較 * 如果dir大於等於0,那麼看當前節點的右節點是否為空,如果為空,就可以把要新增的元素作為當前節點的右節點,如果不為空,還需要下一輪繼續比較 * 如果以上兩條當中有一個子節點不為空,這個if中還做了一件事,那就是把p已經指向了對應的不為空的子節點,開始下一輪的比較 */ if ((p = (dir <= 0) ? p.left : p.right) == null) { // 如果恰好要新增的方向上的子節點為空,此時節點p已經指向了這個空的子節點 Node<K,V> xpn = xp.next; // 獲取當前節點的next節點 TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn); // 建立一個新的樹節點 if (dir <= 0) xp.left = x; // 左孩子指向到這個新的樹節點 else xp.right = x; // 右孩子指向到這個新的樹節點 xp.next = x; // 連結串列中的next節點指向到這個新的樹節點 x.parent = x.prev = xp; // 這個新的樹節點的父節點、前節點均設定為 當前的樹節點 if (xpn != null) // 如果原來的next節點不為空 ((TreeNode<K,V>)xpn).prev = x; // 那麼原來的next節點的前節點指向到新的樹節點 moveRootToFront(tab, balanceInsertion(root, x));// 重新平衡,以及新的根節點置頂 return null; // 返回空,意味著產生了一個新節點 } } }