jdk8會對鏈表進行樹化改造,以免hash衝突帶來的鏈表過長,操做效率低下的問題.經過put時確認位置,理解hashMap鏈表的數據結構.才能明白樹化數組
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
jdk8會對鏈表進行樹化改造,邏輯以下:效率
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) { // 樹化改造邏輯 } }