1. 程式人生 > 實用技巧 >JAVA 資料結構 HashMap

JAVA 資料結構 HashMap

JAVA-HashMap

HashMap是一種特殊的資料結構。既然是資料結構,就一定有應用的場景,不然哪些JDK大牛搞這個幹啥。
問題:

Q1 它能幹啥?

Q2 有什麼特別的?

Q3 有什麼優點?

A1: 當我們需要存放key-value pair 鍵值對的時候,就可以使用這個結構

A2: 名字裡面能帶hash,說明它和hash有關;而且可以允許存放‘空’的鍵值對。

A3: 既然是map,說明有快速查詢value的優勢。

HashMap它很好的解決了儲存和查詢K-V的問題。
在JDK1.7中,它自身的結構是陣列+連結串列來實現的,陣列中的每一個元素都是一個連結串列。通過計算key的hashcode來把hashcode相同的存放在相同的陣列元素中。

在JDK1.8中,底層結構發生了變化當一個Entry鏈中大於8個元素時,就會轉變為紅黑樹

結構已經有了初步的認識,怎麼用,用的時候關注哪些問題?
容量問題:因為HashCode計算返回int範圍高達+-21億,不算負數,所以陣列範圍就可以支援那麼大。但是超大的容量會帶來各種各樣的問題,所以HashMap的預設容量是16。
使用中會不會超出容量?
當然有可能超過預設的16,當想hashmap新增超過一定數量的KV,就會觸發自動擴容,每次容量增加一倍,即16-32-64……。如果hashmap經常觸發擴容的話,會導致效能影響很大,所以儘量設定好容量之後,避免擴容。

HashMap什麼時候會擴容,擴容的原則是什麼?擴容的規則。
HashMap有一個引數負載因子loadfactor,JDK中預設0.75,如果hashmap中的kv到達容量*

負載因子,例如16*0.75=12,到達12個KV就會自動擴容從16擴充套件到32,而且要重新確定索引位置。當然使用者也可以自己定義負載因子,但是不建議自己定義。因子太大,空間利用率越大,但是查詢速度就會變慢,因子太小,空間就會有很多浪費。

原始碼

類定義

類定義常量

鍵值對

擴容

put

get

連結串列轉紅黑樹

put

首先檢查table是不是null,如果為空,就resize初始化table。
如果計算(n - 1) & hash值對應的為空就直接插入一個新node。如果已經存在了就要判斷hash,k,v,如果hash,key都一樣,就會根據條件將之前的v覆蓋;如果hash,key

不一致就會新插入node(而且會根據節點型別,插入樹節點還是連結串列節點),如果k,v 數量大於閾值,就會觸發擴容resize

get

根據key 計算hash,並且去查詢HashMap是否存在這個節點。根據hash和key確認(n - 1) & hash和key是否相等,如果有就取出返回,如果沒有就沒有查到。

一些問題

看完以上,對HashMap基本算是瞭解了。還有一些比較雜的問題,可能大家都會有一些疑惑,但是並沒有在意,因為不會影響使用。

hashMap的長度是2的冪次?

通過(n - 1) & hash來決定桶的位置?

簡單來說,是為了更有效的減少碰撞的機率,從而能夠有效提高效率。如果想要詳細瞭解,可以去看一下hashmap的hash原始碼。

HashMap為什麼執行緒不安全

執行緒安全問題必然是在多執行緒的情況下發生,如果有2個執行緒threadA,threadB,
threadA要插入一個kv到hashmap中,在做put的操作時, 時間片剛好結束,threadB開始執行,要把一個kv插到hashmap中,併成功插入。如果2個執行緒使用的是一樣的,這個時候threadA就會把threadB的記錄覆蓋掉。