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) { // 树化改造逻辑 } }