final Node
Node
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
// 1 判断老表的容量是否超过最大容量值:如果超过则将阈值设置为 Integer.MAX_VALUE ,并直接返回
// 此时 oldCap * 2 比 Integer.MAX_VALUE 大,因此无法进行重新分布,只是单纯的将阈值扩容到最大
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
// 将 newCap 赋值为 oldCap 的 2 倍,如果 newCap< 最大容量并且 oldCap>=16, 则将新阈值设置为原来的两倍
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold : 24
}
//2. 如果老表的容量为 0, 老表的阈值大于 0, 是因为初始容量被放入阈值,则将新表的容量设置为老表的阈值
else if (oldThr > 0)
newCap = oldThr;
else {
//3. 老表的容量为 0, 老表的阈值为 0 ,这种情况是没有传初始容量的 new 方法创建的空表,将阈值和容量设置为默认值。
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
// 4. 如果新表的阈值为空 , 则通过新的容量 * 负载因子获得阈值
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE);
}
// 将当前阈值设置为刚计算出来的新的阈值,定义新表,容量为刚计算出来的新容量,将 table 设置为新定义的表。
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node
table = newTab;
// 6. 如果老表不为空,则需遍历所有节点,将节点赋值给新表
if (oldTab != null) {
// 把每个 bucket 都移动到新的 buckets 中
for (int j = 0; j < oldCap; ++j) {
Node
if ((e = oldTab[j]) != null) { // 将索引值为 j 的老表头节点赋值给 e
oldTab[j] = null; // 将老表的节点设置为空 , 以便垃圾收集器回收空间
//7. 如果 e.next 为空 , 则代表老表的该位置只有 1 个节点,外汇跟单gendan5.com计算新表的索引位置 , 直接将该节点放在该位置
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
//8. 如果是红黑树节点,则进行红黑树的重 hash 分布 ( 跟链表的 hash 分布基本相同 )
else if (e instanceof TreeNode)
((TreeNode
else {
// 9. 如果是普通的链表节点,则进行普通的重 hash 分布
Node
Node
Node
do {
next = e.next;
// 如果 e 的 hash 值与老表的容量进行与运算为 0, 则扩容后的索引位置跟老表的索引位置一样
if ((e.hash & oldCap) == 0) {
if (loTail == null) // 如果 loTail 为空 , 代表该节点为第一个节点
loHead = e; // 则将 loHead 赋值为第一个节点
else
loTail.next = e; // 否则将节点添加在 loTail 后面
loTail = e; // 并将 loTail 赋值为新增的节点
}
// 如果 e 的 hash 值与老表的容量进行与运算为非 0, 则扩容后的索引位置为 : 老表的索引位置+ oldCap
else {
if (hiTail == null) // 如果 hiTail 为空 , 代表该节点为第一个节点
hiHead = e; // 则将 hiHead 赋值为第一个节点
else
hiTail.next = e; // 否则将节点添加在 hiTail 后面
hiTail = e; // 并将 hiTail 赋值为新增的节点
}
} while ((e = next) != null);
// 10. 如果 loTail 不为空(说明老表的数据有分布到新表上“原索引位置”的节点),则将最后一个节点的 next 设为空,并将新表上索引位置为“原索引位置”的节点设置为对应的头节点
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
// 11. 如果 hiTail 不为空(说明老表的数据有分布到新表上“原索引 +oldCap 位置”的节点),则将最后一个节点的 next 设为空,并将新表上索引位置为“原索引 +oldCap ”的节点设置为对应的头节点
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
//12. 返回新表
return newTab;
}