HashMap1.8的扩容机制非常好玩,首先将扩容的代码揪出来
if (oldTab != null) {
//oldCap为原数组的长度
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)
//如果是红黑树结构,就调用split
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
//如果数组中存放的是链表,会将原来的链表
分成两条链表
Node<K,V> loHead =o null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
//通过计算e.hash&oldCap==0构造一条链
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
} //通过e.hash&oldCap!=0构造另外一条链
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
//遍历结束以后,将tail指针指向null
//e.hash&oldCap==0构造而来的链的位置不变
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
//e.hash&oldCap!=0构造而来的链的位置在数
//组j+oldCap位置处
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
这里暂时只介绍链表,红黑树结构暂时还只了解概念
为什么说扩容机制很好玩呢,因为它会将原来的链表同过计算e.hash&oldCap==0分成两条链表,再将两条链表散列到新数组的不同位置上
上张图:生动形象
hashmap扩容
扩容前数组长度为8,扩容为原数组长度的2倍即16。
原来有一条链表在tab[2]的位置,扩容以后仍然有一条链在tab[2]的位置,另外一条链在tab[2+8]即tab[10]的位置处。
多线程情况,对hashmap进行put操作会引起resize,并可能会造成数组元素的丢失