JAVA系列:HashMap常見問題

NIO4444發表於2020-10-13

目錄

HashMap的key可以重複嗎?

為什麼用它

“當兩個物件的hashcode相同會發生什麼?”

“HashMap怎麼解決碰撞?”

“如果兩個鍵的hashcode相同,你如何獲取值物件?”

“如果HashMap的大小超過了負載因子(load factor)定義的容量,怎麼辦?”

“你瞭解重新調整HashMap大小存在什麼問題嗎?”

為什麼String, Interger這樣的wrapper類適合作為鍵? 

我們可以使用自定義的物件作為鍵嗎? 

我們可以使用CocurrentHashMap來代替Hashtable嗎?


HashMap的key可以重複嗎?

也就是說:如果key相同,但是hashcode不同,那麼value不會被覆蓋

                 如果key相同,並且hashCode相同,那麼value會被覆蓋

為什麼用它

譬如HashMap可以接受null鍵值和值,而Hashtable則不能;

HashMap是非synchronized;HashMap很快;以及HashMap儲存的是鍵值對等等。 

 

“當兩個物件的hashcode相同會發生什麼?”

因為hashcode相同,所以它們的bucket位置相同,‘碰撞’會發生。因為HashMap使用連結串列儲存物件,這個Entry(包含有鍵值對的Map.Entry物件)會儲存在連結串列中。

 

“HashMap怎麼解決碰撞?”

HashMap使用連結串列來解決碰撞問題,當發生碰撞了,物件將會儲存在連結串列的下一個節點中。

 

“如果兩個鍵的hashcode相同,你如何獲取值物件?”

當我們呼叫get()方法,HashMap會使用鍵物件的hashcode找到bucket位置,找到bucket位置之後,會呼叫keys.equals()方法去找到連結串列中正確的節點,最終找到要找的值物件。完美的答案!

一些優秀的開發者會指出使用不可變的、宣告作final的物件,並且採用合適的equals()和hashCode()方法的話,將會減少碰撞的發生,提高效率。不可變性使得能夠快取不同鍵的hashcode,這將提高整個獲取物件的速度,使用String,Interger這樣的wrapper類作為鍵是非常好的選擇。

 

“如果HashMap的大小超過了負載因子(load factor)定義的容量,怎麼辦?”

預設的負載因子大小為0.75,也就是說,當一個map填滿了75%的bucket時候,和其它集合類(如ArrayList等)一樣,將會建立原來HashMap大小的兩倍的bucket陣列,來重新調整map的大小,並將原來的物件放入新的bucket陣列中。這個過程叫作rehashing,因為它呼叫hash方法找到新的bucket位置。

 

“你瞭解重新調整HashMap大小存在什麼問題嗎?”

當重新調整HashMap大小的時候,確實存在條件競爭,因為如果兩個執行緒都發現HashMap需要重新調整大小了,它們會同時試著調整大小。在調整大小的過程中,儲存在連結串列中的元素的次序會反過來,因為移動到新的bucket位置的時候,HashMap並不會將元素放在連結串列的尾部,而是放在頭部,這是為了避免尾部遍歷(tail traversing)。如果條件競爭發生了,那麼就死迴圈了。

 

 

 

為什麼String, Interger這樣的wrapper類適合作為鍵? 

String, Interger這樣的wrapper類作為HashMap的鍵是再適合不過了,而且String最為常用。因為String是不可變的,也是final的,而且已經重寫了equals()和hashCode()方法了。其他的wrapper類也有這個特點。不可變性是必要的,因為為了要計算hashCode(),就要防止鍵值改變,如果鍵值在放入時和獲取時返回不同的hashcode的話,那麼就不能從HashMap中找到你想要的物件。不可變性還有其他的優點如執行緒安全。如果你可以僅僅通過將某個field宣告成final就能保證hashCode是不變的,那麼請這麼做吧。因為獲取物件的時候要用到equals()和hashCode()方法,那麼鍵物件正確的重寫這兩個方法是非常重要的。如果兩個不相等的物件返回不同的hashcode的話,那麼碰撞的機率就會小些,這樣就能提高HashMap的效能。

 

我們可以使用自定義的物件作為鍵嗎? 

這是前一個問題的延伸。當然你可能使用任何物件作為鍵,只要它遵守了equals()和hashCode()方法的定義規則,並且當物件插入到Map中之後將不會再改變了。如果這個自定義物件時不可變的,那麼它已經滿足了作為鍵的條件,因為當它建立之後就已經不能改變了。

 

我們可以使用CocurrentHashMap來代替Hashtable嗎?

這是另外一個很熱門的面試題,因為ConcurrentHashMap越來越多人用了。我們知道Hashtable是synchronized的,但是ConcurrentHashMap同步效能更好,因為它僅僅根據同步級別對map的一部分進行上鎖。ConcurrentHashMap當然可以代替HashTable,但是HashTable提供更強的執行緒安全性。

相關文章