1 java.util.HashMap#resize()方法源码解析
- 保存原来数据(扩容阈值、容量大小、具体数据等)
- 判断oldCap。
- 如果大于0,说明之前已经初始化过。
- 如果旧容量已经超过最大容量,将阈值设置到最大。返回原有数组,让其碰撞。
- 如果新容量是旧容量右移一位得到。新容量大于默认容量16,小于最大容量,将原来阈值扩大两倍。
- 如果旧阈值大于零。初始化容器,并设置为阈值
- 初始阈值为0,表示采用默认初始化过程。
- 创建新容量的node数组。容量为旧容量的2倍。
- 采用for循环依次遍历旧Tab。
- 如果索引为 j 处的只有一个数据,用e.hash&(newCapacity-1) 算出新位置,直接放入
- 如果索引为 j 处的node为红黑树。采用红黑树的散列方式
- 红黑树和链表都是采用lo和hi两个链表暂时存放数据。套路和下面链表一样。
- 判断lo和hi的元素个数。
- 如果小于等于6,则将treeNode转化为普通Node。
- 如果超过6,就进行树化处理,和put的树化处理一样。
- 如果索引为 j 处的node为链表。 用lo和hi的两个链表存放此处的数据。
- 如果该节点node.hash(也就是key的hash)&oldCap == 0 。就放在原位置。
- 散列过程中,先用loTail的子节点设置为要散列数据,然后loTail再设置为散列数据,最后将子节点数据置null。保证没有重复,在置null前,最后一个和上一个loTail是相同的。
- 如果该节点node.hash(也就是key的hash)&oldCap != 0。就放在原位置+oldCap。
- 散列过程中,先用hiTail的子节点设置为要散列数据,然后hiTail再设置为散列数据,最后将子节点数据置null。保证没有重复,在置null前,最后一个和上一个hiTail是相同的。
- 最后将lo和hi的Head放入数组的 j 位置。
2 具体源码解析
2.1 resize() 扩容总方法
final Node<K,V>[] resize() {
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;
} else if (oldThr > 0)
newCap = oldThr;
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"})
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;
}
2.2 split() 红黑树的散列方式
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
TreeNode<K,V> b = this;
TreeNode<K,V> loHead = null, loTail = null;
TreeNode<K,V> hiHead = null, hiTail = null;
int lc = 0, hc = 0;
for (TreeNode<K,V> e = b, next; e != null; e = next) {
next = (TreeNode<K,V>)e.next;
e.next = null;
if ((e.hash & bit) == 0) {
if ((e.prev = loTail) == null)
loHead = e;
else
loTail.next = e;
loTail = e;
++lc;
}
else {
if ((e.prev = hiTail) == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
++hc;
}
}
if (loHead != null) {
if (lc <= UNTREEIFY_THRESHOLD)
tab[index] = loHead.untreeify(map);
else {
tab[index] = loHead;
if (hiHead != null)
loHead.treeify(tab);
}
}
if (hiHead != null) {
if (hc <= UNTREEIFY_THRESHOLD)
tab[index + bit] = hiHead.untreeify(map);
else {
tab[index + bit] = hiHead;
if (loHead != null)
hiHead.treeify(tab);
}
}
}