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,且是非無窮大的數字

 

負載因子為什么會影響HashMap性能

首先回憶HashMap的數據結構,

我們都知道有序數組存儲數據,對數據的索引效率都很高,但是插入和刪除就會有性能瓶頸(回憶ArrayList),

鏈表存儲數據,要一次比較元素來檢索出數據,所以索引效率低,但是插入和刪除效率高(回憶LinkedList),

兩者取長補短就產生了哈希散列這種存儲方式,也就是HashMap的存儲邏輯.

而負載因子表示一個散列表的空間的使用程度,有這樣一個公式: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().

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM