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().

相關文章
相關標籤/搜索