簡介之HashMap和Hashtable的區別

 

HashMap和Hashtable的區別

1.底層結構不同

1.1繼承體系的區別

HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類(注:此類已過時。新的實現應該實現 Map 接口,而不是擴展此類)。它們都實現了同時實現了Map、Cloneable(可複製)、Serializable(可序列化)這三個接口。
 

1.2內部實現使用的數組初始化和擴容方式不同
Hashtable:
(1) Hashtable繼承於Dictionary類,實現了Map接口。Map是"key-value鍵值對"接口,Dictionary是聲明瞭操作"鍵值對"函數接口的抽象類。 
(2) Hashtable是通過"拉鍊法"實現的哈希表。它包括幾個重要的成員變量:table, count, threshold, loadFactor, modCount。
  table是一個Entry[]數組類型,而Entry實際上就是一個單向鏈表。哈希表的"key-value鍵值對"都是存儲在Entry數組中的。 
  count是Hashtable的大小,它是Hashtable保存的鍵值對的數量。 
  threshold是Hashtable的閾值,用於判斷是否需要調整Hashtable的容量。threshold的值="容量*加載因子"。
  loadFactor就是加載因子。 
  modCount是用來實現fail-fast機制的

HashMap:
(1) HashMap內存儲數據的Entry數組默認是16,如果沒有對Entry擴容機制的話,當存儲的數據一多,Entry內部的鏈表會很長,這就失去了HashMap的存儲意義了。所以HasnMap內部有自己的擴容機制。HashMap內部有:
    變量size,它記錄HashMap的底層數組中已用槽的數量;
    變量threshold,它是HashMap的閾值,用於判斷是否需要調整HashMap的容量(threshold = 容量*加載因子) 
    變量DEFAULT_LOAD_FACTOR = 0.75f,默認加載因子爲0.75
HashMap擴容的條件是:當size大於threshold時,對HashMap進行擴容
  

​   Hashtable在不指定容量的情況下的默認容量爲11,而HashMap爲16,Hashtable不要求底層數組的容量一定要爲2的整數次冪,而HashMap則要求一定爲2的整數次冪。​      
   Hashtable擴容時,將容量變爲原來的2倍加1,而HashMap擴容時,將容量變爲原來的2倍。


2. 線程安全性的不同
(1)Hashtable是線程安全的,HashMap是線程非安全的。Hashtable的方法是synchronized的,而HashMap不是。
    HashMap是Hashtable的輕量級實現(非線程安全的實現)。
    synchronized意味着在一次僅有一個線程能夠更改Hashtable。就是說任何線程要更新Hashtable時要首先獲得同步鎖,其它線程要等到同步鎖被釋放之後才能再次獲得同步鎖更新Hashtable。

(2)HashMap運行效率高:線程非安全,計算hash值的方式更快,擴容直接*2(位運算<<1)
    Hashtable運行效率低:線程安全,計算hash值速度慢,擴容方式需要的時間相對長。

(3)HashMap就是爲了提高運行速度設計的,相對於Hashtable而言,其計算hash值更容易產生“碰撞”現象,HashMap產生碰撞就以鏈表結構存儲。HashMap的默認空間較大,時間換空間,都是在提高效率。
    
(4)在單線程環境時HashMap效率更高,在多線程中Hashtable能避免死鎖,但是JDK1.5新增了concurrent包,引入線程安全的ConcurrentHashMap,使得Map也可以線程安全。它引入了一個“分段鎖”的概念,不是所有方法都是同步的,因此效率相比Hashtable更高。所以儘管HashMap和Hashtable非常相似,但現在Hashtable已經很少用了(何況它還不符合駝峯命名規則)。

3. 對null的存儲支持不同

HashMap允許存儲1個null鍵和多個null值
Hashtable不允許存儲null鍵和null值


1      public synchronized V put(K key, V value) {
2         // Make sure the value is not null
3         if (value == null) {
4             throw new NullPointerException();
5         }

7         // Makes sure the key is not already in the hashtable.
8         Entry<?,?> tab[] = table;
9         int hash = key.hashCode();
10         int index = (hash & 0x7FFFFFFF) % tab.length;
11         @SuppressWarnings("unchecked")
12         Entry<K,V> entry = (Entry<K,V>)tab[index];
13         for(; entry != null ; entry = entry.next) {
14             if ((entry.hash == hash) && entry.key.equals(key)) {
15                 V old = entry.value;
16                 entry.value = value;
17                 return old;
18             }
19         }
20 
21         addEntry(hash, key, value, index);
22         return null;
23     }

根據上面的部分Hashtable源碼,可以看出value==null時會拋出異常。在key.hashCode();中如果key爲null也會拋出異常。
 

4.遍歷方式的內部實現上不同
(1)Hashtable、HashMap都使用了 Iterator。而由於歷史原因,Hashtable還使用了Enumeration的方式 。
(2)HashMap的Iterator是fail-fast迭代器。當有其它線程改變了HashMap的結構(增加,刪除,修改元素),將會拋出ConcurrentModificationException。不過,通過Iterator的remove()方法移除元素則不會拋出ConcurrentModificationException異常。但這並不是一個一定發生的行爲,要看JVM。
(3)JDK8之前的版本中,Hashtable是沒有fast-fail機制的。在JDK8及以後的版本中 ,HashTable也是使用fast-fail的

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

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

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

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

6.小結

(1)基類不同:HashTable基於Dictionary類,而HashMap是基於AbstractMap。Dictionary是什麼?它是任何可將鍵映射到相應值的類的抽象父類,而AbstractMap是基於Map接口的骨幹實現,它以最大限度地減少實現此接口所需的工作。
(2)線程安全:HashMap時單線程安全的,Hashtable是多線程安全的。
(3)null不同:HashMap可以允許存在一個爲null的key和任意個爲null的value,但是HashTable中的key和value都不允許爲null。
(4)遍歷不同:HashMap僅支持Iterator的遍歷方式,Hashtable支持Iterator和Enumeration兩種遍歷方式。
(5)hash值計算方法不同,HashMap效率更高。
(6)Hashtable:JDK1.0開始。線程安全,效率低。不允許null鍵和null值
​     HashMap:JDK1.2開始。線程不安全,效率高。允許null鍵和null值

ps:詳細原理大家可以百度更詳細的底層實現。

更多免費技術資料可關注:annalin1203

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