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) {
        // 树化改造逻辑
    }
}
相关文章
相关标签/搜索