Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null) //说明单链表只有一个节点 直接复制
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode) //红黑树复制
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order //单链表多节点 复制
Node<K,V> loHead = null, loTail = null;//代表原数组长度(16)以内的位置
Node<K,V> hiHead = null, hiTail = null;//扩容后大于原数组长度的位置
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) { //代表不需要改变位置的元素
if (loTail == null)
loHead = e;
else
loTail.next = e; //第二次进来的节点直接next
loTail = e;
}
else { //代表需要改变位置的元素
if (hiTail == null)
hiHead = e;
else
hiTail.next = e; //节点复制 直接next
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead; //新数组中 原数组长度的位置 元素赋值
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead; //新数组中 扩容部分的位置 元素赋值
}
}
}
}
}
小结:
1. 总共三个情况 (hashmap 扩容 原数据复制)
a. 单链表只有一个节点复制 b. 红黑树复制 c. 单链表多节点复制
2. 需要改变位置的节点并没有重新计算数组下标 而是直接采用 原数组下标+原数组长度