1. 程式人生 > >Java中的HashMap的工作原理是什麽?

Java中的HashMap的工作原理是什麽?

內部實現 它的 閾值 索引 查看 解決 family 空間 並且

Java中的HashMap是以鍵值對(key-value)的形式存儲元素的。HashMap需要一個hash函數,它使用hashCode()和equals()方法來向集合/從集合添加和檢索元素。當調用put()方法的時候,HashMap會計算key的hash值,然後把鍵值對存儲在集合中合適的索引上。如果key已經存在了,value會被更新成新值。HashMap的一些重要的特性是它的容量(capacity),負載因子(load factor)和擴容極限(threshold resizing)。


hashmap是一個key-value鍵值對的數據結構,從結構上來講在jdk1.8之前是用數組加鏈表的方式實現,jdk1.8加了紅黑樹,hashmap數組的默認初始長度是16,hashmap數組只允許一個key為null,允許多個value為null


hashmap的內部實現,hashmap是使用數組+鏈表+紅黑樹的形式實現的,其中數組是一個一個Node[]數組,我們叫他hash桶數組,它上面存放的是key-value鍵值對的節點。HashMap是用hash表來存儲的,在hashmap裏為解決hash沖突,使用鏈地址法,簡單來說就是數組加鏈表的形式來解決,當數據被hash後,得到數組下標,把數據放在對應下表的鏈表中。
然後再說一下hashmap的方法實現
put方法,put方法的第一步,就是計算出要put元素在hash桶數組中的索引位置,得到索引位置需要三步,去put元素key的hashcode值,高位運算,取模運算,高位運算就是用第一步得到的值h,用h的高16位和低16位進行異或操作,第三步為了使hash桶數組元素分布更均勻,采用取模運算,取模運算就是用第二步得到的值和hash桶數組長度-1的值取與。這樣得到的結果和傳統取模運算結果一致,而且效率比取模運算高

jdk1.8中put方法的具體步驟,先判斷hashmap是否為空,為空的話擴容,不為空計算出key的hash值i,然後看table[i]是否為空,為空就直接插入,不為空判斷當前位置的key和table[i]是否相同,相同就覆蓋,不相同就查看table[i]是否是紅黑樹節點,如果是的話就用紅黑樹直接插入鍵值對,如果不是開始遍歷鏈表插入,如果遇到重復值就覆蓋,否則直接插入,如果鏈表長度大於8,轉為紅黑樹結構,執行完成後看size是否大於閾值threshold,大於就擴容,否則直接結束
get方法就是計算出要獲取元素的hash值,去對應位置取即可。
擴容機制,hashmap的擴容中主要進行兩部,第一步把數組長度變為原來的兩倍,第二部把舊數組的元素重新計算hash插入到新數組中,在jdk1.8時,不用重新計算hash,只用看看原來的hash值新增的一位是零還是1,如果是1這個元素在新數組中的位置,是原數組的位置加原數組長度,如果是零就插入到原數組中。擴容過程第二部一個非常重要的方法是transfer方法,采用頭插法,把舊數組的元素插入到新數組中。

3.hashmap大小為什麽是2的冪次方
在計算插入元素在hash桶數組的索引時第三步,為了使元素分布的更加均勻,用取模操作,但是傳統取模操作效率低,然後優化成h&(length-1),設置成2冪次方,是因為2的冪次方-1後的值每一位上都是1,然後與第二步計算出的h值與的時候,最終的結果只和key的hashcode值本身有關,這樣不會造成空間浪費並且分布均勻,如果不是2的冪次方
如果length不為2的冪,比如15。那麽length-1的2進制就會變成1110。在h為隨機數的情況下,和1110做&操作。尾數永遠為0。那麽0001、1001、1101等尾數為1的位置就永遠不可能被entry占用。這樣會造成浪費,不隨機等問題。

Java中的HashMap的工作原理是什麽?