Map、HashMap、TreeMap、LinkedHashMap
Map
與Set接口一樣,Map也是一個接口不能實例化
Map是一種鍵(key)-值(value)對集合,Map中的每個元素都是一個鍵值對,其中key只能有一個為null且key不能重復(唯一),而value可以有多個為null且value可以重復(不唯一),當key值重復寫入時,新寫入的value值會覆蓋原有的值。
Map提供的是一種映射關系,能夠實現通過key快速的查找value
HashMap
- 底層數據結構:數組+鏈表+紅黑樹實現(JDK1.8之后,JDK1.8之前是數組+鏈表):具體實現見底部:-)(哈希表)
- 是否有序:無序
- 是否排序:否
- 是否允許存入null:允許:且null作為key時,總是存儲在hashtable第一個節點上,但最好不要這樣用,出現問題的話,排查比較麻煩。
- 是否線程安全:線程不安全
- 如何解決線程不安全的問題:(1).多線程環境中推薦使用ConcurrentHashMap (2).在多線程環境下若使用HashMap需要使用Collections.synchronizedMap()方法來獲取一個線程安全的集合
來,上個代碼
測試結果
直接輸出: {null=123, 張三豐=12, 張無忌=null, 張捕頭=null} 使用迭代器輸出: key:null value:123--key:張三豐 value:12--key:張無忌 value:null--key:張捕頭 value:null-- keySet遍歷key: key:null value:123--key:張三豐 value:12--key:張無忌 value:null--key:張捕頭 value:null-- 不使用迭代器,直接使用Entry輸出: key:null value:123--key:張三豐 value:12--key:張無忌 value:null--key:張捕頭 value:null--TreeMap
- 底層數據結構:紅黑樹
- 是否有序:無序
- 是否排序:是,按照key排序
- key能否為null:不能,因為沒有null的比較方法,但value可以為null
- 是否線程安全:線程不安全
基于紅黑樹實現。TreeMap沒有調優選項,因為該樹總處于平衡狀態。
基于紅黑二叉樹的NavigableMap的實現,存入TreeMap的元素應當實現Comparable接口或者實現Comparator接口,會按照排序后的順序迭代元素,兩個相比較的key不得拋出classCastException。主要用于存入元素的時候對元素進行自動排序,迭代輸出的時候就按排序順序輸出
來個代碼
再加盤代碼吧
public static void main(String[] args) {TreeMap<Integer, String> tm=new TreeMap<>();tm.put(3, "王");tm.put(1, "孟");tm.put(2, "李");System.out.println("直接輸出"+tm);System.out.println("firstKey():"+"key="+tm.firstKey()+" value="+tm.get(tm.firstKey()));System.out.println("higherKey():"+"key="+tm.higherKey(tm.firstKey())+" value="+tm.get(tm.higherKey(tm.firstKey())));System.out.println("subMap():"+tm.subMap(1, 3));System.out.println("subMap():"+tm.subMap(1, false, 3, true));System.out.println("ceilingKey():"+tm.ceilingKey(2));System.out.println("ceilingEntry():"+tm.ceilingEntry(2));System.out.println("higherEntry():"+tm.higherEntry(2));System.out.println("headMap():"+tm.headMap(2));//排序后,輸出從firstkey開始到secondkey之間的所有key-value對,不包括secondkey;System.out.println("headMap():"+tm.headMap(2,true));System.out.println("tailMap():"+tm.tailMap(2));System.out.println("tailMap():"+tm.tailMap(2, false));//若不加第二個參數,默認為true;System.out.println("descendingKeySet():"+tm.descendingKeySet());//倒序輸出TreeMap的key值System.out.println("descendingMap():"+tm.descendingMap());//倒序輸出TreeMap的key-valueSystem.out.println("containsKey():"+tm.containsKey(2));System.out.println("containsValue():"+tm.containsValue("李"));} 直接輸出{1=孟, 2=李, 3=王} firstKey():key=1 value=孟 higherKey():key=2 value=李 subMap():{1=孟, 2=李} subMap():{2=李, 3=王} ceilingKey():2 ceilingEntry():2=李 higherEntry():3=王 headMap():{1=孟} headMap():{1=孟, 2=李} tailMap():{2=李, 3=王} tailMap():{3=王} descendingKeySet():[3, 2, 1] descendingMap():{3=王, 2=李, 1=孟} containsKey():true containsValue()truekey=iter.next();可以獲取key的值
分析:雖然使用keyset及entryset來進行遍歷能取得相同的結果,
但兩者的遍歷速度是有差別的。
keySet():迭代后只能通過get()取key;再根據key值取value。
entrySet():迭代后可以e.getKey(),e.getValue()取key和value。
說明:keySet()的速度比entrySet()慢了很多,也就是keySet方式遍歷Map的性能不如entrySet性能好
為了提高性能,以后多考慮用entrySet()方式來進行遍歷。
LinkedHashMap
- 底層數據結構:雙向鏈表
- 是否有序:有序
- 是否排序:不排序
- 是否允許鍵值對為空:允許有一個鍵為空,多個值為空
- 是否線程安全:線程不安全
- 是否允許重復的key值:不允許,會覆蓋掉原key的value
上個線程代碼吧
public static void main(String[] args) {LinkedHashMap<String, String> lhm=new LinkedHashMap<>();for (int i = 0; i <=30; i++) {new Thread(()->{lhm.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 8));System.out.println(lhm);},String.valueOf(i)).start();}}測試結果
java.util.ConcurrentModificationExceptionHashTable
- 底層數據結構:JDK1.8之前是數組+鏈表,JDK1.8之后是數組+鏈表+紅黑樹
- 是否有序:無序
- 是否排序:否
- 是否線程安全:是
- 是否允許鍵值對為null:不允許
- 是否允許有重復的元素:不允許,重復的key所對應的value會覆蓋原本的value。
從源碼上看:
HashTable繼承Dictionary,實現了Map接口
照例來盤代碼:
又好像沒什么必要吧,畢竟用法和HashMap一樣,多了個線程安全
數組+鏈表+紅黑樹:
如下圖所示,就是這樣滴:
寫一些大致過程吧:以HashMap<String,Integer>為例:首先,你開始了put("張",1);
而put的源碼是:
這里要注意hash(key)是計算你傳入的key的哈希值,然后調用putVal()函數開始存儲。
進入putVal()后會經過一系列判斷;比如新加入的key的HashCode值所對應的位置在Entry數組中是否已經存儲了別的值。如果沒有,直接寫入。如果有,則判斷key是否相等,不相等的話再繼續判斷next是否有值,有值的話,還需要知道是紅黑樹還是鏈表,然后再根據各自的方法判斷添加。如果是鏈表,還需要在添加完成后判斷是否需要轉成紅黑樹。如果上面這些都沒有,而是直接添加在Entry數組中的話,需要判斷一下是否要擴容。
具體源碼分析可以看這篇博客:href="https://blog.csdn.net/m0_37914588/article/details/82287191
總結
以上是生活随笔為你收集整理的Map、HashMap、TreeMap、LinkedHashMap的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Set 、HashSet、TreeSet
- 下一篇: List、Vector、ArraryLi