HashMap另外一种扩容情况
总所周知hashMap扩容的方法是resize();
纵观hashMap源码调用resize的代码也就几个地方
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
..............
上面两段代码都是put数据的时候判断是否需要进行扩容来调用resize()
但其实还有个地方会调用resize()
final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
do {
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}
是的 你没看错! treeifyBin是map中链表转红黑树的方法。里面竟然有调用resize();
这块代码的逻辑简单来说就是 如果map的数组某个位置链表长度大于8.需要转红黑树。但是数组长度小于MIN_TREEIFY_CAPACITY(64) 就会进行扩容,而不是转红黑树。
我们可以通过自己自定义对象重写hashcode 给一个固定值来模拟链表转红黑树,map默认长度16,threshold=12。当你往map里插入8个hashcode一样的元素时候。通过debug就可以看到容器被扩容 长度为32了。
这里比较懒,代码可以各位自己实验。