转化红黑树:
在put方法中,逻辑是链表长度大于(TREEIFY_THRESHOLD -1)时,就转化为红黑树, 实际情况这只是初步判断,在转化的方法treeifyBin()方法中会进行二次校验,当tab.length
这个函数大概的作用就是:高16bit不变,低16bit和高16bit做了一个异或。根据注释及个人理解,这样的做的原因是因为Java中对象的哈希值都32位整数,高位与低位异或一下能保证高低位都能参与到下标计算中,即使在table长度比较小的情况下,也能尽可能的避免碰撞。
举例:
通过以上计算,也正好证明,为什么广州会成为上海的next节点。
5.3 resize实现 final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; // 获取原HashMap数组的长度。 int oldThr = threshold; // 扩容临界值 int newCap, newThr = 0; if (oldCap > 0) { // 超过最大值就不再扩充了 if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } // 没超过最大值,就扩充为原来的2倍 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold } else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { // zero initial threshold signifies using defaults newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } // 计算新的resize上限 if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; // 遍历桶,然后对桶中的每个元素进行重新hash if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; // 原table地址释放 // 单节点处理 if (e.next == null) newTab[e.hash & (newCap - 1)] = e; // 重新hash放入新table中 // 红黑树处理 else if (e instanceof TreeNode) ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); else { // preserve order // 长链表处理 Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; // 新表是旧表的两倍容量,以下把单链表拆分为高位链表、低位链表 if ((e.hash & oldCap) == 0) { // 低位链表,注意与的对象是oldCap,而不是 oldCap-1 if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { // 高位链表 if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); // 低位链表保持原索引放入新table中 if (loTail != null) { loTail.next = null; newTab[j] = loHead; } // 高位链表放入新table中,索引=原索引+oldCap if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; }从resize() 的实现中可以看出,在扩容时,针对table,如果桶的位置是单节点链表,那么index =(hash & (newTab.length - 1)),直接放入新表。红黑树另外处理。若是多节点链表,会产生高低和低位链表,即:hash & length=0为低位链表、hash & length=length为高位链表。低位链表保持原索引放入新table中,高位链表index=oldTab.index + oldTab.length = hash & (newTab.length-1)。