JDK1.8源码 resize()解析
final HashMap.Node<K,V>[] resize() {
HashMap.Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold; //threshold在table未初始化时存储的是构造方法中tableSizeFor(initialCapacity)的值,如果未带参数initialCapacity,则是0;**tableSizeFor()方法不懂可以看之前的博客**
int newCap, newThr = 0;
if (oldCap > 0) { //HashMap中添加过元素的情况下oldCap才会大于0,否则未初始化oldTab==null,oldCap==0;
if (oldCap >= MAXIMUM_CAPACITY) { //原来的容量大于等于HashMap最大容量,给临界值赋值为一个四位整型的最大值,大约为MAXIMUM_CAPACITY的两倍(MAXIMUM_CAPACITY=2^30=1073741824,Integer.MAX_VALUE=2147483647)
threshold = Integer.MAX_VALUE;
return oldTab;
//这段代码整体意思就是 因为添加过元素之后,临界值是容量的0.75倍,达到这个值就会扩容,因为容量已经达到最大,所以给临界值设置一个达不到的值,为的就是以后再进行添加元素时,不会再扩容;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY) //添加过元素的扩容,直接容量和临界值扩大两倍
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr; //未添加元素的时,进行初始化,因为oldThr=threshold存储的是构造方法中tableSizeFor(initialCapacity)的值,所以这里newCap得到的值是初始化容量大小
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
//未调用initialCapacity的有参构造方法,进行默认大小赋值
}
if (newThr == 0) { //当上述代码执行第二个条件语句时,newThr未进行赋值,所以在这里赋值;
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
//其实就是容量newCap的0.75倍
}
threshold = newThr;//重新给临界值赋值,第一次调用resize()过后都不在存储初始容量
@SuppressWarnings({"rawtypes","unchecked"})
HashMap.Node<K,V>[] newTab = (HashMap.Node<K,V>[])new HashMap.Node[newCap];
table = newTab;
if (oldTab != null) { //把oldTab上的元素移动到newTab上
for (int j = 0; j < oldCap; ++j) {
HashMap.Node<K,V> e;
if ((e = oldTab[j]) != null) {//遍历oldTab
oldTab[j] = null;
if (e.next == null)//如果oldTab[j]上只存在一个节点,直接挂到newTab上
newTab[e.hash & (newCap - 1)] = e;//[e.hash & (newCap - 1)]计算下标,不懂可参考之前的博客
else if (e instanceof TreeNode)//如果是树节点,则进行树处理,有点复杂,不展开多讲,有兴趣自己去了解。嘻嘻~
((HashMap.TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order 这里是对oldTab[j]存在不止一个节点时,进行处理
HashMap.Node<K,V> loHead = null, loTail = null;//这两个节点是维护一个位置未发生变化的链表(维护oldTab[j]下位置不变的节点)
HashMap.Node<K,V> hiHead = null, hiTail = null;//这两个节点是维护一个位置发生变化的链表(维护oldTab[j]下位置变化的节点)
//因为原来的元素位置可能保持不变,可能是原来位置加上原来的oldTab长度:
//hash(不变情况): 0000 0000 0000 0010
//oldCap(16)-1: 0000 0000 0000 1111
//newCap(32)-1: 0000 0000 0001 1111
//hash(变化情况): 0000 0000 0001 0010
//按位与运算,我们可以明显的看出,不变情况的两种计算的结果是[2],而位置变化情况两种计算结果分别是[2],[18];
HashMap.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;//直接把维护位置不变的链表头结点挂在newTab[j]上
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;//直接把维护位置变化的链表头结点挂在newTab[j + oldCap]上
}
}
}
}
}
return newTab;
}
啃源码不易,有收获的小伙伴点个赞哦~