HashMap1.8会在两处resize,一处是在第一次put元素时初始化table,
另一处是在table的size大于threshold时需要扩容(threshold = table.的capacity * loadFactor;)
/**
* Initializes or doubles table size. If null, allocates in
* accord with initial capacity target held in field threshold.
* Otherwise, because we are using power-of-two expansion, the
* elements from each bin must either stay at same index, or move
* with a power of two offset in the new table.
*
* @return the table
*/
final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;//旧表,需要扩容的table或者还未初始化的table
int oldCap = (oldTab == null) ? 0 : oldTab.length;//旧表的容量
int oldThr = threshold;//旧表的扩容阈值
int newCap, newThr = 0;//新表的容量,新表的扩容阈值
if (oldCap > 0) {//旧表容量不为0,表示table已经初始化了//旧表容量已经达到最大值,则返回旧表,不再扩容
if (oldCap >= MAXIMUM_CAPACITY) {
//更新当前的阈值为int的最大值,下次判断threshold已是最大值则不再扩容。
threshold = Integer.MAX_VALUE;
return oldTab;
}//旧表容量扩大一倍得到新容量,新容量未超过最大临界值且旧表容量大于等于默认初始容量,旧表的扩容阈值也同样扩大一倍得到新表的扩容阈值
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}//以下两种情况为table还未初始化,oldThr > 0为调用了HashMap的有参构造函数,threshold已有值;另一种情况为调用了//HashMap的无参构造函数else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;//新表容量为threshold
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;//新表容量为默认初始容量
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);//新表扩容阈值为默认加载因子*默认初始容量
}//else if (oldThr > 0) 这个分支,newThr=0,计算新表阈值
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;
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);//链表尾部元素为null,将两条链表头结点放入新表中对应下标位置
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;//新表下标位置=旧表下标索引+旧表容量oldCap
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
扩容后索引重排,下图为旧表