在学习HashMap源码的过程中,可以经常看到数组容量不够时,会调用resize对数组进行扩容,扩容的过程可以简单理解为:把旧数组中的节点复制到放大一倍的新数组中这是一个较为耗时的过程。
那么该如何减少扩容的发生呢?最直接的方法肯定是一开始就给够一个合适的容量。
在之前的文章HashMap源码学习——初探中提到,HashMap数组的长度需要是2的N次幂,如果采用默认长度DEFAULT_INITIAL_CAPACITY = 16,后续无论如何扩容(每次扩容长度*2)肯定都可以满足。那么这个默认容量的HashMap是怎么创建出来的呢?先看一下HashMap无参的构造函数,也就是平时“偷懒”或未知存储元素数量时经常调用的:
/**
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* (16) and the default load factor (0.75).
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
可以看出,该无参构造函数也很“偷懒”,只设置了一个把默认加载子DEFAULT_LOAD_FACTOR (0.75)赋值给了变量floadFactor。DEFAULT_INITIAL_CAPACITY是什么时候赋值到真正的容量呢?让我们继续往下看,第一次调用put方法时,会出现如下判断
//如果数组(哈希表)为null或者长度为0,则初始化数组
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
邻家table初长成,她还是个null,也就很自然的执行了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) {
//超过最大容量就不扩容了