HashMap、Hashtable、TreeMap、LinkedHashMap、IdentityHashMap、ConcurrentHashMap和WeakHashMap的區別

一、Map概述

java爲數據結構中的映射定義了一個接口java.util.Map;它有三個實現類,分別是HashMap、Hashtable 和TreeMap.

Map是用來存儲鍵值對的數據結構,在數組中通過數組下標來對其內容進行索引的,而在Map中,則是通過對象來進行索引,用來索引的對象叫做key,其對應的對象叫value。

 

二、類圖

 

注:以下說的無序的意思是指不會記錄插入的順序,也不會根據特定規則進行排序

 

三、HashMap和Hashtable的區別

Hashmap 是一個最常用的Map,它根據鍵的HashCode值存儲數據,根據鍵可以直接獲取它的值,具有很快的訪問速度。由於HashMap與Hashtable都採用了hash法進行索引,因此二者具有許多相似之處,它們主要有如下的一些區別:

1.HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在於HashMap允許空(null)鍵值(key)(但需要注意,最多隻允許一條記錄的鍵爲null,不允許多條記錄的值爲null),而Hashtable不允許。

2. HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因爲contains方法容易讓人引起誤解。 Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現。

3.Hashtable的方法是同步的,這個類中的一些方法加入了synchronized關鍵字,保證了Hashtable中的對象是線程安全的。而HashMap不支持線程的同步,所以它不是線程安全的。在多個線程訪問Hashtable時,不需要開發人員對它進行同步,而對於HashMap,開發人員必須提供額外的同步機制。所以,就效率來言,HashMap可能高於Hashtable。

4.Hashtable使用Enumeration,HashMap使用Iterator。

5.Hashtable和HashMap採用的hash/rehash算法都大概一樣,所以一般來說性能不會有很大的差別。

注意:

它們都可以用於多線程的環境,但是當Hashtable的大小增加到一定的時候,性能會急劇下降,因爲迭代時需要被鎖定很長的時間。因爲HashMap引入了分割(segmentation),不論它變得多麼大,僅僅需要鎖定map的某個部分,而其它的線程不需要等到迭代完成才能訪問map。簡而言之,在迭代的過程中,HashMap僅僅鎖定map的某個部分,而Hashtable則會鎖定整個map。

6.在Hashtable中,hash數組默認大小是11,增加的方式是old*2+1。在HashMap中,hash數組的默認大小是16,而且一定是2的指數。

7.hash值的使用不同,Hashtable直接使用對象的HashCode。

注意事項:

1.不能保證其中的鍵值對順序

2.儘量不要使用可變對象作爲它們的key值。(https://mp.csdn.net/postedit/84638297,這篇博客下方有標題:爲什麼要同時重寫equals和hashcode方法,其中有對此的解釋)

 

如何實現HashMap的同步

HashMap可以通過Map m=Collections.synchronizedMap(new HashMap())來達到同步的效果。具體而言,該方法返回一個同步的Map,該Map封裝了底層的HashMap的所有方法,使得底層的HashMap即使是在多線程的環境中也是安全的。

 

HashMap存儲結構

hashmap底層是以數組方式進行存儲。將key-value對作爲數組中的一個元素進行存儲。

key-value都是Map.Entry中的屬性。其中將key的值進行hash之後進行存儲,即每一個key都是計算hash值,然後再存儲。每一個Hash值對應一個數組下標,數組下標是根據hash值和數組長度計算得來。

由於不能的key有可能hash值相同,即該位置的數組中的元素出現兩個,對於這種情況,hashmap採用鏈表形式進行存儲。

 

四、WeakHashMap與HashMap區別

WeakHashMap和HashMap類似,二者的不同之處在於WeakHashMap中key採用的是“弱引用”的方式,只要WeakHashMap中的key不再被外部引用,它就可以被垃圾回收器回收。而HashMap中key採用的是“強引用的方式”,當HashMap中的key沒有被外部引用時,只有這個key從HashMap中刪除後,纔可以被垃圾回收器回收。

 

關於WeakHashMap中key值回收的詳細描述:

WeakHashMap是通過散列表table保存Entry(鍵值對);每個Entry實際上就是一個鏈表來實現的。當某“弱鍵”不再被其它對象引用,就會被GC回收時,這個“弱鍵”也同時被添加到ReferenceQueue隊列中。當下一步我們需要操作WeakHashMap時,會先同步table、queue,table中保存了全部的鍵值對,而queue中保存的是GC回收的鍵值對;同步他們,就是刪除table中被GC回收的鍵值對。

 

五、TreeMap

TreeMap實現了SortMap()接口,基於紅黑樹對所有key進行排序

排序方式:自然排序和定製排序

TreeMap的key以TreeSet的方式存儲,對key的要求與TreeSet對元素的要求大體一致。

 

六、LinkedHashMap和HashMap區別

LinkedHashMap 是HashMap的一個子類

1.使用雙向鏈表來維護鍵值對順序。

2.迭代順序和鍵值對的插入順序保持一致,LinkedHashMap需要維護鍵值對的插入順序,所以性能略低於HashMap。

3.在遍歷的時候會比HashMap慢,不過有種情況例外,當HashMap容量很大,實際數據較少時,遍歷起來可能會比 LinkedHashMap慢,因爲LinkedHashMap的遍歷速度只和實際數據有關,和容量無關,而HashMap的遍歷速度和他的容量有關。

 

LinkedHashMap存儲結構

內部存儲的元素的模型

entry是下面這樣的,相比HashMap,多了兩個屬性,一個before,一個after。next和after有時候會指向同一個entry,有時候next指向null,而after指向entry。

LinkedHashMap存儲結構

linkedHashMap和HashMap在存儲操作上是一樣的,但是LinkedHashMap多的東西是會記住在此之前插入的元素,這些元素不一定是在一個桶中,畫個圖。

也就是說,對於linkedHashMap的基本操作還是和HashMap一樣,在其上面加了兩個屬性,也就是爲了記錄前一個插入的元素和記錄後一個插入的元素。也就是隻要和hashmap一樣進行操作之後把這兩個屬性的值設置好,就OK了。注意一點,會有一個header的實體,目的是爲了記錄第一個插入的元素是誰,在遍歷的時候能夠找到第一個元素。

 

七、IdentityHashMap和HashMap的區別

IdentityHashMap與HashMap類似,IdentityHashMap也允許使用null,但不能保證鍵值對順序。

區別:

IdentityHashMap使用==來判斷key是否相等,HashMap使用equals來判斷key是否相等。

 

八、ConcurrentHashMap

底層採用分段的數組+鏈表實現,線程安全

Hashtable的synchronized是針對整張Hash表的,即每次鎖住整張表讓線程獨佔,ConcurrentHashMap允許多個修改操作併發進行,其關鍵在於使用了鎖分離技術

引入了一個“分段鎖”的概念,具體可以理解爲把一個大的Map拆分成N個小的HashTable,根據key.hashCode()來決定把key放到哪個HashTable中。在ConcurrentHashMap中,就是把Map分成了N個Segment,put和get的時候,都是現根據key.hashCode()算出放到哪個Segment中.通過把整個Map分爲N個Segment,可以提供相同的線程安全,但是效率提升N倍,默認提升16倍。(讀操作不加鎖,由於HashEntry的value變量是 volatile的,也能保證讀取到最新的值。)

有些方法需要跨段怎麼辦呢?

比如size()和containsValue(),它們可能需要鎖定整個表而而不僅僅是某個段,這需要按順序鎖定所有段,操作完畢後,又按順序釋放所有段的鎖

如何擴容?

段內擴容(段內元素超過該段對應Entry數組長度的75%觸發擴容,不會對整個Map進行擴容),插入前檢測需不需要擴容,有效避免無效擴容

 

總結:

使用最多的是HashMap。

HashMap裏面存入的鍵值對在取出時沒有固定的順序,是隨機的。一般而言,在Map中插入、刪除和定位元素,HashMap是最好的選擇。

在使用多線程時,考慮線程安全,優先使用HashTable。

由於TreeMap實現了SortMap接口,能夠把它保存的記錄根據鍵排序,因此,取出來的是排序的鍵值對,如果需要按自然順序或自定義順序遍歷鍵,那麼TreeMap會更好。如果需要輸出的順序和輸入的相同,那麼用LinkedHashMap可以實現,它還可以按讀取順序排列。

 

參考博客:

https://www.cnblogs.com/whgk/p/6169622.html

https://blog.csdn.net/junchenbb0430/article/details/78643100

 

 

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