一、概述
- 1.根据不同情况对容量以及阈值进行赋值
- 2.如果旧哈希表不为空,创建新哈希表准备扩容
- 3.遍历旧哈希表
- (1)只有一个头节点的链表,将该头节点重新结算哈希放到新的哈希表
- (2)红黑树
- (3)遍历链表,如果扩容后的下标是否扩容前的相等, JDK1.8关于HashMap扩容时的resize()方法中(e.hash & oldCap) == 0算法讲解.将该节点放到新的哈希表,否则将下标加上扩容前容量放到新的哈希表
二、源码解析
final HashMap.Node<K,V>[] resize() {
HashMap.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) {
//对阈值赋值Integer最大值、直接返回
threshold = Integer.MAX_VALUE;
return oldTab;
}
//旧容量乘二之后的新容量小于最大容量 并且 旧容量大于等于默认容量
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
//新阈值等于旧阈值的二倍
newThr = oldThr << 1; // double threshold
}
//由构造方法可知,如果指定了initialCapacity, 该值被初始化成大于initialCapacity的最小的2的次幂 this.threshold = tableSizeFor(initialCapacity);
//这里这种情况指的是原table为空,并且在初始化的时候指定了initialCapacity
else if (oldThr > 0)
//新容量 = 旧阈值
newCap = oldThr;
//由构造方法可知,如果没有指定initialCapacity, 则不会给threshold赋值, 该值被初始化为0
//这里这种情况指的是原table为空,并且在初始化的时候没有指定容量,
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"})
HashMap.Node<K,V>[] newTab = (HashMap.Node<K,V>[])new HashMap.Node[newCap];
table = newTab;
if (oldTab != null) {
//遍历哈希表
for (int j = 0; j < oldCap; ++j) {
HashMap.Node<K,V> e;
//头节点不等于null
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
//链表只有一个头节点
if (e.next == null)
//将该头节点重新结算哈希放到新的哈希表
newTab[e.hash & (newCap - 1)] = e;
//红黑树,对树进行拆分
else if (e instanceof HashMap.TreeNode)
((HashMap.TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
HashMap.Node<K,V> loHead = null, loTail = null;
HashMap.Node<K,V> hiHead = null, hiTail = null;
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;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}