下面是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().