final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
// 获得老的容量,还没分配表的话为0
int oldCap = (oldTab == null) ? 0 : oldTab.length;
//threshold是扩容的阈值
int oldThr = threshold;
//新的threshold应该是老的两倍.
int newCap, newThr = 0;
//老的table不是null,就要判断一下要扩容到多大
if (oldCap > 0) {
//太大了,不能扩容了,直接返回老的表继续用
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
//还能扩容,那么将在后面进行扩容操作,这里只是把newCap赋值为oldCap的两倍,newThr赋值为oldThr的两倍
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
//原table是null,新的容量threshold.
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
//初始化map的大小为0,用默认值代替
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
// 第一次的threshold是要扩容到多大.但是之后的threshold是触发resize的阈值.所以第一次扩容(即的初始化table)之后,要把threshold设置为阈值而不再是扩容后的大小.
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"})
//新建一个newCap大小的Node数组table来进行rehash
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
//老table不是null进行扩容的话 要执行rehash操作,把老表的值都放到新表当中
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;
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;
loTail = e;
}
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;
}
总结一下resize()里的操作逻辑:
主要有几个变量:
- Node<K,V>[] oldTab = table; 把老的table表放到oldTab引用,后面进行rehash操作
- int oldCap = (oldTab == null) ? 0 : oldTab.length; 老的table的大小,null的话就是0
- int oldThr = threshold; 老的阈值,阈值和容量分开存放,不用每次都要计算了.
- int newCap = 0;新的容量大小 ,初始化为0
- int newThr = 0;新的阈值大小, 初始化为0
进行resize操作的过程(不考虑边界条件)
判断老的table是不是null(oldCap==0),是的话
把newCap也就是新的容量赋值为oldThr(table是null说明是第一次进行扩容,threshold被tableSizeFor设置为了2的幂次).然后把newThr也就是新的阈值赋值为(oldCap*装填因子).
如果传入的初始容量为0,就用默认值16代替.否则的话(即不是第一次初始化table)
newCap赋值为oldCap的两倍,newThr赋值为oldThr的两倍
(上面的步骤主要是在计算应该扩容为多大)
之后将threshold赋值为newThr
新建一个newCap大小Node数组如果老的table不是null,就要把老的Node全部复制到新的table里面
进行rehash操作
因为底层是使用Node数组实现的,而且数组大小已知为oldCap,所以直接遍历数组,对于不是null的数组元素(也就是有Node节点的元素)进行rehash重新找他们在新数组中的位置.最后返回新的table数组