HashMap负载因子

下面是HashMap的一个构造函数,两个参数initialCapacity,loadFactor数组

这关系HashMap的迭代性能。数据结构

 1     /**
 2      * Constructs an empty <tt>HashMap</tt> with the specified initial
 3      * capacity and load factor.
 4      *
 5      * @param  initialCapacity the initial capacity
 6      * @param  loadFactor      the load factor
 7      * @throws IllegalArgumentException if the initial capacity is negative
 8      *         or the load factor is nonpositive
 9      */
10     public HashMap(int initialCapacity, float loadFactor) {
11         if (initialCapacity < 0)
12             throw new IllegalArgumentException("Illegal initial capacity: " +
13                                                initialCapacity);
14         if (initialCapacity > MAXIMUM_CAPACITY)
15             initialCapacity = MAXIMUM_CAPACITY;
16         if (loadFactor <= 0 || Float.isNaN(loadFactor))
17             throw new IllegalArgumentException("Illegal load factor: " +
18                                                loadFactor);
19         this.loadFactor = loadFactor;
20         this.threshold = tableSizeFor(initialCapacity);
21     }

关于这两个参数值的设定界限:函数

1. initialCapacity是map的初始化容量,initialCapacity > MAXIMUM_CAPACITY,代表map的最大容量是1<<30,也就是1左移30位,每左移一位乘以2,因此就是1*2^30=1073741824.性能

2. loadFactor是map的负载因子,loadFactor <= 0 || Float.isNaN(loadFactor),代表负载因子要大于0,且是非无穷大的数字this

 

负载因子为何会影响HashMap性能spa

首先回忆HashMap的数据结构,code

咱们都知道有序数组存储数据,对数据的索引效率都很高,可是插入和删除就会有性能瓶颈(回忆ArrayList),blog

链表存储数据,要一次比较元素来检索出数据,因此索引效率低,可是插入和删除效率高(回忆LinkedList),索引

二者取长补短就产生了哈希散列这种存储方式,也就是HashMap的存储逻辑.ci

而负载因子表示一个散列表的空间的使用程度,有这样一个公式:initailCapacity*loadFactor=HashMap的容量。

因此负载因子越大则散列表的装填程度越高,也就是能容纳更多的元素,元素多了,链表大了,因此此时索引效率就会下降。

反之,负载因子越小则链表中的数据量就越稀疏,此时会对空间形成烂费,可是此时索引效率高

 

如何科学设置 initailCapacity,loadFactor的值

HashMap有三个构造函数,能够选用无参构造函数,不进行设置。默认值分别是16和0.75.

官方的建议是initailCapacity设置成2的n次幂,laodFactor根据业务需求,若是迭代性能不是很重要,能够设置大一下。

 

为何initailCapacity要设置成2的n次幂,网友解释了,我以为很对,如下摘自网友博客:深刻理解HashMap

左边两组是数组长度为16(2的4次方),右边两组是数组长度为15。两组的hashcode均为8和9,可是很明显,当它们和1110“与”的时候,产生了相同的结果,也就是说它们会定

位到数组中的同一个位置上去,这就产生了碰撞,8和9会被放到同一个链表上,那么查询的时候就须要遍历这个链表,获得8或者9,这样就下降了查询的效率。同时,咱们也能够

发现,当数组长度为15的时候,hashcode的值会与14(1110)进行“与”,那么最后一位永远是0,而0001,0011,0101,1001,1011,0111,1101这几个位置永远都不能

存放元素了,空间浪费至关大,更糟的是这种状况中,数组可使用的位置比数组长度小了不少,这意味着进一步增长了碰撞的概率,减慢了查询的效率!

 因此说,当数组长度为2的n次幂的时候,不一样的key算得得index相同的概率较小,那么数据在数组上分布就比较均匀,也就是说碰撞的概率小,相对的,查询的时候就不用

遍历某个位置上的链表,这样查询效率也就较高了。

 

resize()方法

 initailCapacity,loadFactor会影响到HashMap扩容。

HashMap每次put操做是都会检查一遍 size(当前容量)>initailCapacity*loadFactor 是否成立。若是不成立则HashMap扩容为之前的两倍(数组扩成两倍),

而后从新计算每一个元素在数组中的位置,而后再进行存储。这是一个十分消耗性能的操做。

因此若是能根据业务预估出HashMap的容量,应该在建立的时候指定容量,那么能够避免resize().

相关文章
相关标签/搜索