Java集合详解之Map
一.首先看看集合框架體系圖
從圖中可以看到,Map接口擴展了Iterator接口,關于Iterator接口詳解請移步:Iterator接口詳解
二.Map是什么?
Map<k,v>使用鍵值對存儲,map會維護與鍵k相關聯的值v。兩個key可以關聯相同的對象,但key不能重復,常見的key是String類型,但也可以是任何對象。通過鍵就可以找到對應的值,這種數據結構就是Map(映射)
Map接口中定義的方法:
void clear() 
//刪除所有的映射
default V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) 
//嘗試計算指定鍵的映射及其當前映射的值(如果沒有當前映射, null )。  
default V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction) 
/*如果指定的鍵尚未與值相關聯(或映射到 null ),則嘗試使用給定的映射函數計算其值,并將其輸入到此/映射中,除非 null 。 */ 
default V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction) 
//如果指定的密鑰的值存在且非空,則嘗試計算給定密鑰及其當前映射值的新映射。  
boolean containsKey(Object key) 
//如果此映射包含指定鍵的映射,則返回 true 。  
boolean containsValue(Object value) 
//如果此map將一個或多個鍵映射到指定的值,則返回 true 。  
Set<Map.Entry<K,V>> entrySet() 
//返回此map中包含的映射的Set視圖。  
boolean equals(Object o) 
//將指定的對象與此映射進行比較以獲得相等性。  
default void forEach(BiConsumer<? super K,? super V> action) 
//對此映射中的每個條目執行給定的操作,直到所有條目都被處理或操作引發異常。  
V get(Object key) 
//返回到指定鍵所映射的值,或 null  
default V getOrDefault(Object key, V defaultValue) 
//返回到指定鍵所映射的值,或 defaultValue
int hashCode() 
//返回此map的哈希碼值。  
boolean isEmpty() 
//如果此map不包含鍵值映射,則返回 true 。  
Set<K> keySet() 
//返回此map中包含的鍵的Set視圖。  
default V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction) 
//如果指定的鍵尚未與值相關聯或與null相關聯,則將其與給定的非空值相關聯。  
V put(K key, V value) 
//將指定的值與該映射中的指定鍵相關聯(可選操作)。  
void putAll(Map<? extends K,? extends V> m) 
//將指定map的所有映射復制到此映射(可選操作)。  
default V putIfAbsent(K key, V value) 
/*如果指定的鍵尚未與某個值相關聯(或映射到 null )將其與給定值相關聯并返回null,否則返回當前值。  */
V remove(Object key) 
//如果存在(從可選的操作),從該map中刪除一個鍵的映射。  
default boolean remove(Object key, Object value) 
//僅當指定的密鑰當前映射到指定的值時刪除該條目。  
default V replace(K key, V value) 
//只有當目標映射到某個值時,才能替換指定鍵的條目。  
default boolean replace(K key, V oldValue, V newValue) 
//僅當當前映射到指定的值時,才能替換指定鍵的條目。  
default void replaceAll(BiFunction<? super K,? super V,? extends V> function) 
//將每個條目的值替換為對該條目調用給定函數的結果,直到所有條目都被處理或該函數拋出異常。  
int size() 
//返回此map中鍵值映射的數量。  
Collection<V> values() 
//返回此map中包含的值的Collection視圖。  
三.具體實現類
1.HashMap
JDK1.8 之前 HashMap 底層是 數組和鏈表 結合在一起使用也就是 鏈表散列。(關于散列表的知識請移步:集合詳解之Set--散列表)HashMap 通過 key 的 hashCode 經過擾動函數(所謂擾動函數指的就是 HashMap 的 hash 方法。使用 hash 方法也就是擾動函數是為了防止一些實現比較差的 hashCode() 方法 換句話說使用擾動函數之后可以減少碰撞。)處理過后得到 hash 值,然后通過 (n - 1) & hash 判斷當前元素存放的位置(這里的 n 指的是數組的長度),如果當前位置存在元素的話,就判斷該元素與要存入的元素的 hash 值以及 key 是否相同,如果相同的話,直接覆蓋,不相同就通過拉鏈法解決沖突。數據結構如下圖:
JDK1.8 以后的 HashMap 在解決哈希沖突時有了較大的變化,當鏈表長度大于閾值(默認為8)時,將鏈表轉化為紅黑樹,以減少搜索時間。數據結構圖如下:
?
HashMap最多只允許一條記錄的鍵為null,允許多條記錄的值為null。HashMap非線程安全,即任一時刻可以有多個線程同時寫HashMap,可能會導致數據的不一致。如果需要滿足線程安全,可以用 Collections的synchronizedMap方法使HashMap具有線程安全的能力,或者使用ConcurrentHashMap。
2.HashTable
HashTable和HashMap的實現原理幾乎一樣,差別無非是1.HashTable不允許key和value為null;2.HashTable是線程安全的。但是HashTable線程安全的策略實現代價卻太大了,簡單粗暴,get/put所有相關操作都是synchronized的,這相當于給整個哈希表加了一把大鎖,多線程訪問時候,只要有一個線程訪問或操作該對象,那其他線程只能阻塞,相當于將所有的操作串行化,在競爭激烈的并發場景中性能就會非常差。Hashtable不建議在新代碼中使用,不需要線程安全的場合可以用HashMap替換,需要線程安全的場合可以用ConcurrentHashMap替換。數據結構如下圖:
3.LinkedHashMap
LinkedHashMap是HashMap的一個子類,保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的,也可以在構造時帶參數,按照訪問次序排序。看名字也可以猜到,LinkedHashMap就是在HashMap的基礎上加了一個鏈表來保存記錄的插入順序。結構圖如下:
4.TreeMap
TreeMap實現SortedMap接口,能夠把它保存的記錄根據鍵排序,默認是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator遍歷TreeMap時,得到的記錄是排過序的。如果使用排序的映射,建議使用TreeMap。在使用TreeMap時,key必須實現Comparable接口或者在構造TreeMap傳入自定義的Comparator,否則會在運行時拋出java.lang.ClassCastException類型的異常
這里順便提一下Comparable與Comparator的簡單區別:
- comparable是java.lang包下的一個接口,使用compareTo(Object obj)方法來進行排序的。
- comparator是java.util包下的一個接口,使用compare(Object obj1,Object obj2)方法來進行排序的。
參考:Java 8系列之重新認識HashMap
? ? ? ? ?? https://www.cnblogs.com/chengxiao/p/6842045.html
總結
以上是生活随笔為你收集整理的Java集合详解之Map的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 集合详解之Set
- 下一篇: Java集合之并发容器
