1. 程式人生 > >HashMap和HashTable區別及Hash衝突解決方法

HashMap和HashTable區別及Hash衝突解決方法

一、HashMap和HashTable主要有以下5個方面的區別:

1.繼承的父類不同

  Hashtable繼承自Dictionary類,而HashMap繼承自AbstractMap類。但二者都實現了Map介面。

2.對null物件的支援不同

  HashMap是支援null鍵和null值的,而HashTable在遇到null時,會丟擲NullPointerException異常。這並不是因為HashTable有什麼特殊的實現層面的原因導致不能支援null鍵和null值,這僅僅是因為HashMap在實現時對null做了特殊處理,將null的hashCode值定為了0,從而將其存放在雜湊表的第0個bucket中。

3.容量大小及擴容方式不同

  HashMap和HashTable都使用雜湊表來儲存鍵值對。在資料結構上是基本相同的,都建立了一個繼承自Map.Entry的私有的內部類Entry,每一個Entry物件表示儲存在雜湊表中的一個鍵值對。
Entry物件唯一表示一個鍵值對,有四個屬性:
 -K key 鍵物件
 -V value 值物件
 -int hash 鍵物件的hash值
 -Entry entry 指向連結串列中下一個Entry物件,可為null,表示當前Entry物件在連結串列尾部。
  HashMap/HashTable內部用Entry陣列實現雜湊表,而對於對映到同一個雜湊桶(陣列的同一個位置)的鍵值對,使用Entry連結串列來儲存。
  HashMap/HashTable初始容量大小和每次擴充容量大小的不同:HashTable預設的初始大小為11,之後每次擴充為原來的2n+1。HashMap預設的初始化大小為16,之後每次擴充為原來的2倍。如果在建立時給定了初始化大小,那麼HashTable會直接使用你給定的大小,而HashMap會將其擴充為2的冪次方大小。

4.執行緒安全性不同

  HashTable是同步的(原因:公開的方法比如get都使用了synchronized描述符。而遍歷檢視比如keySet都使用了Collections.synchronizedXXX進行了同步包裝),HashMap不是,也就是說HashTable在多執行緒使用的情況下,不需要做額外的同步,而HashMap則不行。
  由於Hashtable是執行緒安全的也是synchronized,所以在單執行緒環境下它比HashMap速度要慢。
  如果要保持執行緒安全可以選用ConcurrentHashMap,ConcurrentHashMap引入了分割(segmentation),不論它變得多麼大,僅僅需要鎖定map的某個部分,而其它的執行緒不需要等到迭代完成才能訪問map。Hashtable則會鎖定整個map,Hashtable的大小增加到一定的時候,效能會急劇下降,因為迭代時需要被鎖定很長的時間。簡而言之,在迭代的過程中,ConcurrentHashMap僅僅鎖定map的某個部分,而Hashtable則會鎖定整個map,ConcurrentHashMap比Hashtable高效。

5.Hash值不同

  Hashtable計算hash值,直接用key的hashCode(),而HashMap重新計算了key的hash值,Hashtable在求hash值對應的位置索引時,用取模運算,而HashMap在求位置索引時,則用與運算,且這裡一般先用hash&0x7FFFFFFF後,再對length取模,&0x7FFFFFFF的目的是為了將負的hash值轉化為正值,因為hash值有可能為負數,而&0x7FFFFFFF後,只有符號位改變,而後面的位都不變。

二、Hash衝突解決方法

  雜湊(Hash)衝突:當關鍵字集合很大時,關鍵字值不同的元素可能會映像到雜湊表的同一地址上,即K1!=K2,但f(K1)=f(K2),這種現象稱為hash衝突。散列表要解決的一個問題就是雜湊值的衝突問題,通常有4種解決衝突的方法:
  (1)、連結串列法(鏈地址法):將相同hash值的物件組織成一個連結串列放在hash值對應的槽位,其中一個物件會記錄下一個物件的地址;
  (2)、開放地址法:通過一個探測演算法,當某個槽位已經被佔據的情況下繼續查詢下一個可以使用的槽位;
  (3)、再Hash法:同時構造多個不同的雜湊函式,當一個出現衝突時用另一個,直至沒有衝突發生。這種方法不易產生聚集,但增加了計算時間。
  (4)、建立公共溢位區:將雜湊表分為基本表和溢位表兩部分,凡是和基本表發生衝突的元素,一律填入溢位表。
  HashMap和Hashtable Hash衝突解決的方法採用的都是連結串列法,連結串列是單向連結串列。

總結:

       1、Hashmap總體比Hashtable高效,建議使用Hashmap,考慮執行緒安全的話,可以使用ConcurrentHashMap;
       2、JDK8 中雜湊衝突過多,連結串列會轉紅黑樹,時間複雜度是O(logn),不會是O(n),提高效率;
       3、hashCode的存在主要是用於查詢的快捷性,如Hashtable,HashMap等,hashCode是用來在雜湊儲存結構中確定物件的儲存地址的。