HashMap_get方法實現解析

1 get()

    /**
     * Returns the value to which the specified key is mapped,
     * or {@code null} if this map contains no mapping for the key.
     *
     * <p>More formally, if this map contains a mapping from a key
     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
     * key.equals(k))}, then this method returns {@code v}; otherwise
     * it returns {@code null}.  (There can be at most one such mapping.)
     *
     * <p>A return value of {@code null} does not <i>necessarily</i>
     * indicate that the map contains no mapping for the key; it's also
     * possible that the map explicitly maps the key to {@code null}.
     * The {@link #containsKey containsKey} operation may be used to
     * distinguish these two cases.
     *
     * @see #put(Object, Object)
     */
    public V get(Object key) {
        Node<K,V> e;
		
		// hash(key) 獲取key的hash
		// e = getNode(hash(key), key) 通過筒的hash和key獲取節點
		// 返回節點的值
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

    /**
     * Implements Map.get and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {

		// tab 數組加鏈表
		// first 鏈表(第一個節點)
		// e 鏈表
		// n 數組總長度
		// k 節點的鍵
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;

		// tab = table 獲取數組加鏈表
		// n = tab.length 獲取數組的長度(筒的數量)
		// (n - 1) & hash 當前筒的定位下標
		// first = tab[(n - 1) & hash] 獲取鏈表(第一個節點)
		// 如果數組加鏈表不爲空並且當前筒不爲空
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {

			// k = first.key 獲取節點的key
			// 若如果筒存在,並且,節點存在
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                // 返回
                return first;

			// e = first.next 獲取下一個節點
			// 如果下一個節點不爲空
            if ((e = first.next) != null) {

				// 如果當前節點類型是或黑樹節點
                if (first instanceof TreeNode)
                	// (TreeNode<K,V>)first 轉化當前鏈表爲紅黑樹
                	// 在樹中獲取指定節點,並且,返回
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);

				// 如果下一個節點類型不是紅黑樹節點(鏈表節點)
                do {

					// k = e.key 獲取下一個節點的key
					// 如果當前節點筒一致,並且key一致
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        // 返回節點
                        return e;

				// e = e.next 獲取當前節點的下一個節點
				// 如果下一個節點不爲空,執行do
                } while ((e = e.next) != null);
            }
        }
        // 返回空
        return null;
    }

2 getTreeNode()

        /**
         * Calls find for root node.
         */
        final TreeNode<K,V> getTreeNode(int h, Object k) {

			// root() 獲取根節點
			// find() 從紅黑樹中獲取指定hash和key的樹節點
			// 從根節點或當前紅黑樹,獲取指定節點,並返回
            return ((parent != null) ? root() : this).find(h, k, null);
        }
        
        /**
         * Returns root of tree containing this node.
         */
        final TreeNode<K,V> root() {

			// 獲取當前節點
            for (TreeNode<K,V> r = this, p;;) {

				// p = r.parent 獲取當前節點的父節點
				// 如果父節點不存在
                if ((p = r.parent) == null)
                	// 返回當前節點
                    return r;

				// 如果父節點存在,賦值父節點爲當前節點
                r = p;
            }
        }
        
        /**
         * Finds the node starting at root p with the given hash and key.
         * The kc argument caches comparableClassFor(key) upon first use
         * comparing keys.
         */
        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {

			// 獲取樹(當前節點)
            TreeNode<K,V> p = this;
            do {

				// ph 當前節點的hash
				// dir 樹的所有層級?當前節點的層級位置?
				// pk 當前節點的鍵
				// pl 當前節點的(左子樹)左節點
				// pr 當前節點的(右子樹)右節點
				// q 臨時節點
                int ph, dir; K pk;
                TreeNode<K,V> pl = p.left, pr = p.right, q;
                
				// ph = p.hash 獲取當前節點的hash
				// 如果當前節點的hash大於查找節點的hash值
				if ((ph = p.hash) > h)
					// 將左節點設置爲當前節點,即,小的方向查找
                    p = pl;

				// 如果當前節點的hash小於查找節點的hash值
                else if (ph < h)
                	// 將右節點設置爲當前節點,即,大的方向查找
                    p = pr;

				// pk = p.key 獲取節點的key
				// 如果節點的key匹配
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                	// 返回該節點
                    return p;
                
                // 如果hash相等,key不匹配,左節點爲空
                else if (pl == null)
                	// 獲取右節點
                    p = pr;

				// 如果hash相等,key不匹配,右節點爲空
                else if (pr == null)
                	// 獲取左節點
                    p = pl;

				// kc = comparableClassFor(k) 獲取鍵的類型
				// dir = compareComparables(kc, k, pk) 校驗鍵的類型,返回校驗結果,
				// 如果鍵的類型存在,並且,匹配當前節點
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    // 如果鍵的類型xxx,獲取左節點,獲取右節點;
                    p = (dir < 0) ? pl : pr;
                
                // q = pr.find(h, k, kc) 獲節點
                // 如果節點不爲空
                else if ((q = pr.find(h, k, kc)) != null)
                	// 返回節點
                    return q;

				// 賦值左子節點爲當前節點
                else
                    p = pl;

			// 繼續遍歷下一個節點
            } while (p != null);

			// 沒有獲取到節點返回null
            return null;
        }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章