1. 源码
final Node<K,V>[] resize() {
/**
* 1. oldCap > 0 首先确定扩容后的table长度newCap
* - 如果超过MAXIMUM_CAPACITY(1<<30)则不再扩容
* - 否则扩容2倍(2 * oldCap < MAXIMUM_CAPACITY && oldCap > 16)
newThr = oldThr << 1;
* 2. oldThr > 0 (initial capacity was placed in threshold)
* - 这里oldCap == 0,表示表是空的,但是有oldThr,所有newCap = oldThr;
* 3. oldCap == 0 && oldThr == 0 (zero initial threshold signifies using defaults)
这里表示表是空的并且oldThr = 0,则
* -newCap = DEFAULT_INITIAL_CAPACITY(16)
* -newThr = 16 * 0.75 = 12
* 4. 如果newThr == 0,求个新的threshold,并且赋给threshold
*/
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) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
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;
else { // zero initial threshold signifies using defaults
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) {
//旧的设置为null,用于GC
oldTab[j] = null;
//如果只有一个node
if (e.next == null)
//只有一个元素,获取新的下标,注意使用的是newCap
//这里注意到新的jdk1.8中hash函数是:高16bit不变,低16bit和高16bit做了一个异或,
然后再(n - 1) & hash获取下标
newTab[e.hash & (newCap - 1)] = e;
//如果是红黑树
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
/**
* 核心主要是这里的扩容机制
* 1. 先说一些概念,扩容后容量翻倍,所以会有低位和高位之分,
低位就是原来的长度,比如(0-15),高位(16-31)
*/
// 1. 定义高低位头尾节点
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
// 2. 临时节点
Node<K,V> next;
do {
next = e.next;
// 3. 利用位运算判断高低位, == 0表示< oldCap,属于低位,可以看下面的分析
if ((e.hash & oldCap) == 0) {
// 4. 利用尾插法插入值
// loTail == null,
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
// 5. 高位同样处理
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
//低位的在原来的index
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
//高位的在新index
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
2. 扩容后如何确定index(e.hash & oldCap)
初始大小1 << 4 = 2^4 = 16
16 扩容成 32,1 << 4 << 1 = 32 高位是1
下面hash1和hash2对oldCap异或操作,
1. hash1高位是0,0 & 1 = 0,在旧的index j
2. hash2高位是1,1 & 1 = 1,高位是1,即相当于j + oldCap
所以扩容不需要重新计算hash值,只需要判断原来的hash值和oldCap位运算,利用高位确定
16扩容成32:
e.hash & oldCap 举个例子:
Map map = new HashMap<>(8,0.75f);
map.put("1","1");
map.put("2","2");
map.put("3","3");
map.put("10","10");
map.put("18","18");
map.put("6","6");
map.put("7","7");
map.put("8","8");
System.out.println(map);
初始大小8,负载因子0.75f,长度到达7就会扩容,debug会发现
oldCap = 8
10的hash值是1567
0110 0001 1111
0000 0000 1000 与运算 = 8 高位
18的hash值是1575
0110 0010 0111
0000 0000 1000 与运算 = 0 低位