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
);
}
}
}