HashMap 與HashTable的區別

相同點

1.底層數據結構:都爲數組 + 鏈表;

2.key都不能重複,value可以重複;

3.插入元素都不能保證插入有序;

4.哈希過程通過key進行哈希;

5.實現接口:Map<K,V>,Cloneable,java.io.Seriliable;

不同點

1、發佈時間不同

Hashtable是java發佈時就提供的鍵值映射的數據結構,而HashMap產生於JDK1.2。HashMap已經成爲應用最爲廣泛的一種數據類型,然而Hashtable基本上已經被棄用了,一方面雖然線程安全但是效率比較低,還有一方面可能是因爲Hashtable沒有遵循駝峯命名法。

2、繼承的父類不同

HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類(已經廢棄)。

不過它們都實現了同時實現了map、Cloneable(可複製)、Serializable(可序列化)這三個接口

3、對外提供的方法不同

Hashtable比HashMap多提供了elments() 和contains() 兩個方法。

elments() 方法繼承自Hashtable的父類Dictionnary。elements() 方法用於返回此Hashtable中的value的枚舉。

contains()方法判斷該Hashtable是否包含傳入的value。它的作用與containsValue()一致。事實上,contansValue() 就只是調用了一下contains() 方法。

4、對Null key 和Null value的支持不同

Hashtable既不支持Null key也不支持Null value。Hashtable的put()方法的註釋中有說明。

當key爲Null時,調用put() 方法,運行到箭頭這一步就會拋出空指針異常,因爲拿一個Null值去調用方法了。

當value爲null值時,Hashtable對其做了限制,運行到紅框框這一步也會拋出空指針異常。

HashMap中,null可以作爲鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值爲null。當get()方法返回null值時,可能是 HashMap中沒有該鍵,也可能使該鍵所對應的值爲null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵, 而應該用containsKey()方法來判斷。

5、線程安全不同

Hashtable是線程安全的,因爲它的每個方法中都加入了Synchronize方法。在多線程併發的環境下,可以直接使用Hashtable,不需要自己爲它的方法實現同步。

HashMap不是線程安全的,在多線程併發的環境下,可能會產生死鎖等問題,使用HashMap時就必須要自己增加同步處理。。原因是在擴容時會有兩個步驟:先擴容(創建一個新的Entry空數組,長度是原來的2倍,Hash的規則隨之改變)再Rehash(Hash公式:int index = (length - 1) & hash;)

雖然HashMap不是線程安全的,但是它的效率會比Hashtable要好很多。這樣設計是合理的。在我們的日常使用當中,大部分時間是單線程操作的。HashMap把這部分操作解放出來了。當需要多線程操作的時候可以使用線程安全的ConcurrentHashMap。ConcurrentHashMap雖然也是線程安全的,但是它的效率比Hashtable要高好多倍。因爲ConcurrentHashMap使用了分段鎖,並不對整個數據進行鎖定。

6、初識容量大小和每次擴充容量大小不同

Hashtable默認的初始大小爲11,之後每次擴充,容量變爲原來的2n+1。HashMap默認的初始化大小爲16。之後每次擴充,容量變爲原來的2倍。

創建時,如果給定了容量初始值,那麼Hashtable會直接使用你給定的大小,而HashMap會將其擴充爲2的冪次方大小。也就是說Hashtable會盡量使用素數、奇數。而HashMap則總是使用2的冪作爲哈希表的大小。

之所以會有這樣的不同,是因爲Hashtable和HashMap設計時的側重點不同。Hashtable的側重點是哈希的結果更加均勻,使得哈希衝突減少。當哈希表的大小爲素數時,簡單的取模哈希的結果會更加均勻。而HashMap則更加關注hash的計算效率問題。在取模計算時,如果模數是2的冪,那麼我們可以直接使用位運算來得到結果,效率要大大高於做除法。HashMap爲了加快hash的速度,將哈希表的大小固定爲了2的冪。當然這引入了哈希分佈不均勻的問題,所以HashMap爲解決這問題,又對hash算法做了一些改動,從而導致了Hashtable和HashMap的計算hash值的方法不同。

7、計算hash值的方法不同

爲了得到元素的位置,首先需要根據元素的 KEY計算出一個hash值,然後再用這個hash值來計算得到最終的位置。

Hashtable直接使用對象的hashCode。hashCode是JDK根據對象的地址或者字符串或者數字算出來的int類型的數值。然後再使用除留餘數發來獲得最終的位置。

Hashtable在計算元素的位置時需要進行一次除法運算,而除法運算是比較耗時的。
HashMap爲了提高計算效率,將哈希表的大小固定爲了2的冪,這樣在取模預算時,不需要做除法,只需要做位運算。位運算比除法的效率要高很多。

HashMap的效率雖然提高了,但是hash衝突卻也增加了。因爲它得出的hash值的低位相同的概率比較高,而計算位運算

爲了解決這個問題,HashMap重新根據hashcode計算hash值後,又對hash值做了一些運算來打散數據。使得取得的位置更加分散,從而減少了hash衝突。當然了,爲了高效,HashMap只做了一些簡單的位處理,從而不至於把使用2 的冪次方帶來的效率提升給抵消掉。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章