HashMap的性能受到两个参数的影响:初始化容量和负载因子,下面来详细讲述这几个关键问题。(HashMap是常见的数据结构,也是面试和工作中常用到的数据结构,线下可以使用微通过crazy042438一起单点讨论)

1.1 Initial Capacity与Load Factor

Initial Capacity:初始化容量,它表示HashMap底层的那个数组,也就是Entry数组有多长,这个值默认是16。
Load Factor:负载因子,它表示HashMap的负载程度,换句话说,它表示HashMap到底有多满了,是不是需要扩容了,这个值默认是0.75f。
初始化容量和负载因子的默认值是Java官方经过实践和优化得到的数据,可以适应大多数的场景。

当然也可以不使用其默认值,可以在构造的时候,自定义HashMap的容量和负载因子:

//单纯指定容量
Map<String,String> hashMapWithCapacity=newHashMap<>(64)
//自定义容量和负载因子
Map<String,String> hashMapWithCapacityAndLF=newHashMap<>(64,0.9f)

一旦需要自定义容量和负载因子,我们需要搞清楚,他们到底是什么,用来干嘛,会对性能造成什么影响。

一句话:这两个数值会影响到HashMap的扩容,而扩容是一个对性能影响非常大的操作。

1.2 HashMap的扩容

1.2.1 扩容是什么

HashMap的扩容:HashMap被初始化之后,其容量是有限的(可以是默认,也可以是自定义的),当元素不断被插入,是HashMap达到一定的程度(负载因子决定),这个时候,HashMap就会扩容。

根据源码,使用公式表示,是否扩容由容量和负载因子的乘积决定!

触发扩容的条件:

HashMap.Size>=Capacity*LoadFactor

HashMap.Size:当前HashMap的实际元素个数
Capacity:容量
LoadFactor:负载因子
如果在默认值的条件下:

HashMap.Size=16*0.75=12

也就是,默认的情况下,插入十二个元素的时候,就会触发扩容。

1.2.2 扩容的步骤

一旦HashMap的size超过了Capacity * LoadFactor乘积,就会触发扩容,那如何扩容呢?,需要经过两步:

resize:即:创建一个new Entry数组,长度是原来old Entry的2倍。
rehash:遍历old Entry数组,把里面的每一个元素取出来重新计算hash和index。为什么要重新计算呢?想一想之前的index计算公式:
index = hash值 & (length -1)

对,因为长度已经改了,所以index肯定会不一样,举个例子:

当原数组长度为16时,Hash运算是和1111做与运算;
新数组长度为32,Hash运算是和11111做与运算。
Hash结果显然不同。

1.3 容量与性能(常见问题)

综上所述,不同的容量和负载因子的设置,会导致hashmap的扩容频率不一致。所以:

  • Initial Capacity设置得低,存储空间少,但是增加了rehash的频率。 所以如果能够预期到会存储比较多的数据,那么这个值应该设置高一点
  • Initial Capacity设置得高,存储空间多,rehash频率少。但是会增加迭代的成本。 所以总结一个场景
  • Initial Capacity设置高:大量存储,少量迭代
  • Initial Capacity设置低:数据少,迭代频繁

常见问题:

如何扩容的
初始化容量是多少,如何设置,有什么应用场景
负载因子的作用是什么