HashMap容量和負載因子

2021-10-05 17:03:07 字數 1466 閱讀 2869

引自:

hashmap底層資料結構是陣列+鍊錶,jdk1.8中還引入了紅黑樹,當鍊表長度超過8個時,會將鍊錶轉成紅黑樹,以提公升其查詢效能。那麼,給出乙個節點,hashmap是如何確定這個節點應該放在具體哪個位置呢?(以jdk1.8為例)

final v putval

(int hash, k key, v value,

boolean onlyifabsent,

boolean evict)

// 同樣的,如果key已經存在的話,則不進行插入操作,而是後面進行value替換

if(e.hash == hash &&

((k = e.key)

== key ||

(key != null && key.

equals

(k))))

break

; p = e;}}

// e != null的情況,就是key已經存在了,這裡統一進行了新值value,替換舊值e.value的操作

if(e != null)

}++modcount;

// 插入後陣列size 大於閾值的話,需要進行擴容if(

++size > threshold)

resize()

;afternodeinsertion

(evict)

;return null;

}

看原始碼,節點落在陣列中的index = (陣列長度 - 1) & key的hashcode,如果該index上沒有資料,則直接插到該index上,如果節點已經有資料了,則把新節點插入該index對應的鍊錶中(如果鍊錶節點大於8個,會進行鍊錶轉樹,之後的插入演算法就變成了樹的插入演算法)。

每次put之後,會檢測一下是否需要擴容,size超過了 總容量 * 負載因子,則會擴容。預設情況下,16 * 0.75 = 12個。

1、為什麼初始容量是16

當容量為2的冪時,上述n -1 對應的二進位制數全為1,這樣才能保證它和key的hashcode做&運算後,能夠均勻分布,這樣才能減少hash碰撞的次數。至於預設值為什麼是16,而不是2 、4、8,或者32、64、1024等,我想應該就是個折中處理,過小會導致放不下幾個元素,就要進行擴容了,而擴容是乙個很消耗效能的操作。取值過大的話,無疑會浪費更多的記憶體空間。因此在日常開發中,如果可以預估hashmap會存入節點的數量,則應該在初始化時,指定其容量。

2、為什麼負載因子是0.75

也是乙個綜合考慮,如果設定過小,hashmap每put少量的資料,都要進行一次擴容,而擴容操作會消耗大量的效能。如果設定過大的話,如果設成1,容量還是16,假設現在陣列上已經占用的15個,再要put資料進來,計算陣列index時,發生hash碰撞的概率將達到15/16,這違背的hashmap減少hash碰撞的原則。

HashMap 負載因子

static final float default load factor 0.75f 大概意思就是說,在理想情況下,使用隨機雜湊碼,節點出現的頻率在hash桶中遵循泊松分布,同時給出了桶中元素個數和概率的對照表。從上面的表中可以看到當桶中元素到達8個的時候,概率已經變得非常小,也就是說用0.75...

HashMap的負載因子

下面是hashmap的乙個建構函式,兩個引數initialcapacity,loadfactor 這關係hashmap的迭代效能。constructs an empty hashmap with the specified initial capacity and load factor.param...

hashmap 中的初始容量和載入因子之間的聯絡

構造乙個新的空 set,其底層 hashmap 例項具有指定的初始容量和指定的載入因子 public hashset intinitialcapacity,float loadfactor 初始容量 是雜湊表在建立時的容量。載入因子 是雜湊表在其容量自動增加之前可以達到多滿的一種尺度。當雜湊表中的條...