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) {//如果原数组长度大于0,说明已初始化了
if (oldCap >= MAXIMUM_CAPACITY) {//原数组长度大于等于临界值1 << 30(1073741824)就返回原数组不能再扩容,因数扩容都是以两倍扩容,如果再扩容就超过了int类型最大值1 << 31>((1<<31)-1),所以1 << 30是数组最长长度,不能再长了。
threshold = Integer.MAX_VALUE;//int类型最大值(1<<31)-1(12147483647),阀值一般是比数组长度短为什么这时候比数组长度还长((1<<31)-1)>1 << 30,因为这时候阀值已经没用了
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)//1、oldCap << 1先扩容,原数组长度乘2附值给新数组长度,并且判断原数组长度大于16,16第一次put(key,value)时创建的数组长度,就是说这里如果小于16,那就没必要给新的阀值,在后面if (newThr == 0) {那里会计算新的阀值
newThr = oldThr << 1; //这里是原阀值乘2
}
else if (oldThr > 0) //首先想if (oldCap > 0) {这是最多的情况所以放在第一个判断,那有没有可能进到这里呢,一般是就算oldCap 不大于0,oldThr也一样不大于0,但是看了hashmap构造函数后就知道有这种可能了,HashMap(int initialCapacity, float loadFactor)和HashMap(int initialCapacity)两个构造函数会附值给loadFactor加载因子、threshold阀值,无参构造函数只附值给loadFactor加载因子
newCap = oldThr;//原阀值附值给新的数组长度,在后面if (newThr == 0) {那里会计算新的阀值
else {//这里很明显就是无参构造函数对应的创建数组的方法了
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<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;//loHead原数组第一个元素,loTail 原数组最后一个元素
Node<K,V> hiHead = null, hiTail = null;//hiHead新数组第一个元素,hiTail新数组最后一个元素
Node<K,V> next;
do {
next = e.next;
// 注意:不是(e.hash & (oldCap-1));而是(e.hash & oldCap)
// (e.hash & oldCap) 得到的是 元素的在数组中的位置是否需要移动,示例如下
// 示例1:
// e.hash=10 0000 1010
// oldCap=16 0001 0000
// & =0 0000 0000 比较高位的第一位 0
//结论:元素位置在扩容后数组中的位置没有发生改变
// 示例2:
// e.hash=17 0001 0001
// oldCap=16 0001 0000
// & =1 0001 0000 比较高位的第一位 1
//结论:元素位置在扩容后数组中的位置发生了改变,新的下标位置是原下标位置+原数组长度
// (e.hash & (oldCap-1)) 得到的是下标位置,示例如下
// e.hash=10 0000 1010
// oldCap-1=15 0000 1111
// & =10 0000 1010
// e.hash=17 0001 0001
// oldCap-1=15 0000 1111
// & =1 0000 0001
//新下标位置
// e.hash=17 0001 0001
// newCap-1=31 0001 1111 newCap=32
// & =17 0001 0001 1+oldCap = 1+16
//元素在重新计算hash之后,因为n变为2倍,那么n-1的mask范围在高位多1bit(红色),因此新的index就会发生这样的变化:
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;
}
jdk1.8 hashmap.resize方法源码
最新推荐文章于 2024-11-05 20:19:26 发布