jdk 1.8 的HashMap 的樹化

jdk8會對鏈表進行樹化改造,以免hash衝突帶來的鏈表過長,操做效率低下的問題.經過put時確認位置,理解hashMap鏈表的數據結構.才能明白樹化數組

肯定位置--內部hash

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

put方法裏,會進行hash(key)以後的操做,hashMap內部的hash方法以下數據結構

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

能夠看出hashcode值左移16位,獲得的按位且運算符;避免hash高位形成的hash碰撞code

i = (n - 1) & hash 這段是entry插入時在hashMap中實際的位置,得保證tab數組的容量內肯定hash的位置hash

treeify

jdk8會對鏈表進行樹化改造,邏輯以下:效率

  • MIN_TREEIFY_CAPACITY=64; 樹化map最小容量;大於該值則進行樹化改造
  • treeify_threshold=8; binCount大於等於門檻值進入treeifyBin()方法
  • UNTREEIFY_THRESHOLD=6;把樹恢復成鏈表;
for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }

上面是putVal的一段代碼,這裏的binCount是指計算出來的在tab數組裏的位置相同的元素的個數,也就是bucket內元素的數量;jdk

final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        // 樹化改造邏輯
    }
}
相關文章
相關標籤/搜索