final Node<K,V>[] resize() {
// 记录原数组
Node<K,V>[] oldTab = table;
// 记录原长度
int oldCap = (oldTab == null) ? 0 : oldTab.length;
// 记录原扩容阈值
int oldThr = threshold;
// 定义新的数组容量和扩容阈值
int newCap, newThr = 0;
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
// 原长度超过最大值则将阈值设置为最大值 后续则不会扩容
threshold = Integer.MAX_VALUE;
return oldTab;
}
// newCap = oldCap * 2 左移1位相当于原值*2 并且原长度大于16
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
// HashMap有参构造方法(即传入initCapacity)此时原长度为0且阈值不为0(HashMap懒加载)
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
// 无参构造方法生成,使用默认值作为容量和阈值 16 0.75
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
// 定义新的阈值
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数组
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
// 将类实例中的数组引用地址换为新的数组地址
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
// 开始对原数组中的buckets进行循环
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
// 如果只有一个Node 则进行hash计算对应位置赋值
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
// 如果是红黑树 则按照红黑树处理
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
// 1.8之后采用了新的扩容机制,通过
// 原位置的头尾节点
Node<K,V> loHead = null, loTail = null;
// 新位置的头尾节点(原位置+原长度)
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
// 判断hash与原长度位运算得到最高位的值为0
// 表示依旧保留在原位置
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
// 判断hash与原长度位运算得到最高位的值为1
// 表示保留在新位置(原位置+原长度)
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
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;
}
}
}
}
}
return newTab;
}
对于JDK1.8中采用新的扩容方式(为什么JDK1.7中采用了重新计算,JDK1.8中采用原位置和新位置(原位置+原长度)),可以参考:https://blog.csdn.net/qq32933432/article/details/86668385,这篇文章写得非常详细
来自于一位毕业一年半,堕落一年半后重新开始奋发学习的搬砖工的见解。有错误之处还请各位大神斧正!