putVal方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
//省略
if (++size > threshold)
resize();
//省略
}
分析:
1)每次put了一个key-value对后,就会size++,且会比较size和threshold(数组的长度 * 负载因子),resize()方法就是在扩容
if (++size > threshold)
resize();
resize()方法
final Node<K,V>[] resize() {
//省略
if (oldCap > 0) {
//省略
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
//省略
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 { //链表
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);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
1)新数组的大小和负载因子是老数组的2倍
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
2)构建新数组
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
3)如果e.next是null,这个位置的元素不是链表,也不是红黑树。那么此时就用e.hash和 (newCap - 1)做与运算,定位并直接放在新数组里。
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
4)如果该位置是个红黑树节点,会调用split()方法去遍历这颗红黑树,然后将每个节点重新hash寻址,定位找到新数组。
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
5)如果不是上面两种情况,那就是链表。在同一个链表里面的数据在扩容以后会哈希到新数组的两个位置,要么是个index,要么就是index + oldCap。就相当于原来的一个链表扩容后变成了两个链表。
6)这两个表示Rehash后的第1个链表的头尾指针
Node<K,V> loHead = null, loTail = null;
7)这两个表示Rehash后的第2个链表的头尾指针
Node<K,V> hiHead = null, hiTail = null;
8)在do-while循环中对老链表中每一个节点进行遍历,对每一个节点的hash值和oldCap做与运算。结果分为0、1两种情况。为方便讲解,假设oldCap=16,即0001 0000。
如果结果为0,表明hash值第5位为0,那么和(newCap-1)(即31,二进制0001 1111)做与运算的结果与扩容前和(oldCap -1)(即15,二进制0000 1111)的结果一样,也就是这种情况,扩容后到新数组上还是落在原来的index上。
如果结果为1,表明hash值第5位为1,那么和(newCap-1)(即31,二进制0001 1111)做与运算的结果就等于原来的index+oldCap。
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;
}
9)将上面得到的两个链表(通过尾部指针判断是否存在)挂在新的hashmap中。位置分表为index,index+oldCap(原来的位置是index)。
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}