jdk1.8里面HashMap的扩容机制
链表的扩容
HashMap.Node<K,V> loHead = null, loTail = null; HashMap.Node<K,V> hiHead = null, hiTail = null; HashMap.Node<K,V> next; do { next = e.next; /*为什么要和老的数组长度按位与?因为: 数组长度都是2的幂次方,都是00000100000这种的,所以(e.hash & oldCap)的值是否为0,完全取决于oldCap里面的唯一的一个"1" 要么是0,要么不是0 扩容后的位置,要么在原来的位置不变,要么是oldindex+oldCap(原来的下标位置+原来的数组长度) */ if ((e.hash & oldCap) == 0) {//要么在原来的位置不变 if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else {//要么是oldindex+oldCap(原来的下标位置+原来的数组长度) if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); /* 循环结束后,再去放置到新数组上面去: jdk1.8里面是先分组,再放置,分为低位组和高位组,要么在原来的位置不变,要么是oldindex+oldCap(原来的下标位置+原来的数组长度) */ if (loTail != null) {//低位组 loTail.next = null; newTab[j] = loHead; } if (hiTail != null) {//高位组 hiTail.next = null; newTab[j + oldCap] = hiHead; }
红黑树的扩容
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) { TreeNode<K,V> b = this; // Relink into lo and hi lists, preserving order TreeNode<K,V> loHead = null, loTail = null; TreeNode<K,V> hiHead = null, hiTail = null; int lc = 0, hc = 0; //将红黑树拆分成两个链表,这里的逻辑和上面的差不多 for (TreeNode<K,V> e = b, next; e != null; e = next) { next = (TreeNode<K,V>)e.next; e.next = null; if ((e.hash & bit) == 0) { if ((e.prev = loTail) == null) loHead = e; else loTail.next = e; loTail = e; ++lc; } else { if ((e.prev = hiTail) == null) hiHead = e; else hiTail.next = e; hiTail = e; ++hc; } } //低位的不为空,则转移低位 if (loHead != null) { //小于6,则转成链表 if (lc <= UNTREEIFY_THRESHOLD) tab[index] = loHead.untreeify(map); //否则,转成红黑树 else { tab[index] = loHead; //如果hiHead为null,则直接整个树移过去就可以,否则还要树化低位的 if (hiHead != null) // (else is already treeified) loHead.treeify(tab); } } if (hiHead != null) { if (hc <= UNTREEIFY_THRESHOLD) tab[index + bit] = hiHead.untreeify(map); else { tab[index + bit] = hiHead; if (loHead != null) hiHead.treeify(tab); } } }