深入淺出 Map 的實現(HashMap、HashTable、LinkedHashMap、TreeMap)
1、基本介紹
HashMap、TreeMap、HashTable、LinkedHashMap 共同實現了介面java.util.Map, 都是鍵值對形式,且map的key不允許重複
2、詳細介紹
a、HashMap
是一個最常用的Map實現方式,它根據鍵的HashCode 值儲存資料,根據鍵可以直接獲取它的值,具有很快的訪問速度,但是HashMap是無序、執行緒不安全的,且HashMap不同步,如果需要執行緒同步,則可以使用ConcurrentHashMap,也可以使用Collections.synchronizedMap(HashMap
map)方法讓HashMap具有同步的能力。其實同步同步,就看有沒有synchronized關鍵字。 HashMap的key 有且只能允許一個null。至於存取方式我就不說了
注:執行緒不安全(多個執行緒訪問同一個物件或實現進行更新操作時,造成資料混亂)
b、HashTable
HashTable繼承自Dictionary類 ,它也是無序的,但是HashTable是執行緒安全的,同步的,即任一時刻只有一個執行緒能寫HashTable, 但是這也讓HashTable在讀取的時候,速度比HashMap慢,但是寫入速度是比HashMap快的
之前我一直存在一個誤區,以為HashMap的寫入速度比HashTable快,但是測試表明,HashTable的寫入快,讀取慢。測試結果如下:
1、寫入
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Date date1= new Date();
for (int i = 0; i < 1000000; i++) {
map.put(i, i);
}
Date date2 = new Date();
System.out.println("HashMap的插入時間:");
System.out.println(date2.getTime()-date1.getTime());
Map<Integer, Integer> map1 = new Hashtable<Integer, Integer>();
Date date3= new Date();
for (int i = 0; i < 1000000; i++) {
map1.put(i, i);
}
Date date4 = new Date();
System.out.println("HashTable的插入時間:");
System.out.println(date4.getTime()-date3.getTime());
輸出結果:HashMap的插入時間:1420
HashTable的插入時間:797
2、讀取
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < 10000000; i++) {
map.put(i, i);
}
Date date1= new Date();
for (Integer key : map.keySet()) {
map.get(key);
}
Date date2 = new Date();
System.out.println("HashMap的讀取時間:");
System.out.println(date2.getTime()-date1.getTime());
Map<Integer, Integer> map1 = new Hashtable<Integer, Integer>();
for (int i = 0; i < 10000000; i++) {
map1.put(i, i);
}
Date date3= new Date();
for (Integer key : map1.keySet()) {
map1.get(key);
}
Date date4 = new Date();
System.out.println("HashTable的讀取時間:");
System.out.println(date4.getTime()-date3.getTime());
輸出結果:
HashMap的讀取時間:
188
HashTable的讀取時間:
265
c、LinkedHashMap
LinkedHashMap是Map中常用的有序的兩種實現之一, 它儲存了記錄的插入順序,先插入的先遍歷到,就是說你插入是什麼順序,你出來就是什麼順序。
對於LinkedHashMap而言,它繼承與HashMap、底層使用雜湊表與雙向連結串列來儲存所有元素。其基本操作與父類HashMap相似,它通過重寫父類相關的方法,來實現自己的連結列表特性。LinkedHashMap採用的hash演算法和HashMap相同,但是它重新定義了陣列中儲存的元素Entry,該Entry除了儲存當前物件的引用外,還儲存了其上一個元素before和下一個元素after的引用,從而在雜湊表的基礎上又構成了雙向連結列表,效果圖如下:
具體程式碼如下:
Map<String, String> map = new LinkedHashMap<String, String>();
map.put("aw3", "21f");
map.put("dds", "333");
map.put("322", "33s");
map.put("fes", "ada");
map.put("444", "21");
System.out.println("LinkedHashMap的值:" + map);
輸出結果:LinkedHashMap的值:{aw3=21f, dds=333, 322=33s, fes=ada, 444=21}
注:LinkedHashMap在遍歷的時候會比HashMap慢,不過有種情況例外,當HashMap容量很大,實際資料較少時,遍歷起來可能會 比LinkedHashMap慢,因為LinkedHashMap的遍歷速度只和實際資料有關,和容量無關,而HashMap的遍歷速度和他的容量有關
d、TreeMap
TreeMap實現SortMap介面,能夠把它儲存的記錄根據鍵排序,預設是按鍵值的升序排序,也可以指定排序的比較器,當用Iterator 遍歷TreeMap時,得到的記錄是排過序的。
TreeMap的排序原理是:紅黑樹演算法的實現 ,具體概念參考:點選開啟連結 。
它的主要實現是Comparator架構,通過比較的方式,進行一個排序,以下是TreeMap的原始碼
/**
* Compares two keys using the correct comparison method for this TreeMap.
*/
final int compare(Object k1, Object k2) {
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
: comparator.compare((K)k1, (K)k2);
}
我們也可以自定義Comparator, TreeMap進行降序排序,這點是LinkedHashMap不能實現的
具體程式碼如下:
//預設的TreeMap升序排列
Map<String,Integer> map1 = new TreeMap<String,Integer>();
map1.put("a", 222);
map1.put("s", 111);
map1.put("b", 222);
map1.put("d", 222);
System.out.println("map1=" + map1);
//自定義排序方式——降序
Map<String, Integer> map = new TreeMap<String, Integer>(new Comparator<String>() {
/*
* int compare(Object o1, Object o2) 返回一個基本型別的整型,
* 返回負數表示:o1 小於o2,
* 返回0 表示:o1和o2相等,
* 返回正數表示:o1大於o2。
*/
public int compare(String a, String b) {
//這裡的compareTo比較的是字串的ASC碼
return b.compareTo(a);
}
});
map.put("a", 222);
map.put("s", 111);
map.put("b", 222);
map.put("d", 222);
System.out.println("map=" + map);
輸出結果:
map1={a=222, b=222, d=222, s=111}
map={s=111, d=222, b=222, a=222}
注:這裡字串的compareTo 值得注意,因為比較的是ASC碼,所以當字串裡面的值為int型別的時候,可能輸出的結果不是根據數字大小來排序的。例如:
//自定義排序方式——降序
Map<String, Integer> map2 = new TreeMap<String, Integer>(new Comparator<String>() {
/*
* int compare(Object o1, Object o2) 返回一個基本型別的整型,
* 返回負數表示:o1 小於o2,
* 返回0 表示:o1和o2相等,
* 返回正數表示:o1大於o2。
*/
public int compare(String a, String b) {
//這裡的compareTo比較的是字串的ASC碼
return b.compareTo(a);
}
});
map2.put("1", 222);
map2.put("5", 111);
map2.put("22", 222);
map2.put("19", 222);
System.out.println("map2=" + map2);
輸出結果:map2={5=111, 22=222, 19=222, 1=222}
也就是說,當你用Integer做key的時候,比較的方法就需要改變一下, 如下:
//自定義排序方式——降序
Map<String, Integer> map2 = new TreeMap<String, Integer>(new Comparator<String>() {
/*
* int compare(Object o1, Object o2) 返回一個基本型別的整型,
* 返回負數表示:o1 小於o2,
* 返回0 表示:o1和o2相等,
* 返回正數表示:o1大於o2。
*/
public int compare(String a, String b) {
//這裡就是直接比較整型的數值大小
return Integer.parseInt(b) - Integer.parseInt(a);
}
});
map2.put("1", 222);
map2.put("5", 111);
map2.put("22", 222);
map2.put("19", 222);
System.out.println("map2=" + map2);
輸出結果: map2={22=222, 19=222, 5=111, 1=222}
3、總結
1、Map中,HashMap具有超高的訪問速度,如果我們只是在Map 中插入、刪除和定位元素,而無關執行緒安全或者同步問題,HashMap 是最好的選擇。
2、如果考慮執行緒安全或者寫入速度的話,可以使用HashTable
3、如果想按怎麼存的順序怎麼取,比如佇列形式,排排隊。 那麼使用LinkedHashMap吧,怎麼用怎麼爽
4、如果需要讓Map按照key進行升序或者降序排序,那就用TreeMap吧
Map集合強大之處還需要各位的挖掘,如有說錯的地方,還望大家指正,如有補充,也可回覆或私密我
相關文章
- Java集合系列(四):HashMap、Hashtable、LinkedHashMap、TreeMap的使用方法及區別JavaHashMap
- HashMap、LinkedHashMap、HashTable、HashSet筆記HashMap筆記
- Java中HashMap,LinkedHashMap,TreeMap的區別[轉]JavaHashMap
- HashSet/HashMap、TreeSet/TreeMap、LinkedHashSet/LinkedHashMap 區別HashMap
- 【java】【Map】HashMap、Hashtable、CollectionsJavaHashMap
- HashTable、ConcurrentHashMap、TreeMap、HashMap關於鍵值的區別HashMap
- HashMap,LinkedHashMap,TreeMap讀取大量資料效率的比較HashMap
- 深入淺出java的MapJava
- 深入淺出學Java-HashMapJavaHashMap
- 深入淺出一下Java的HashMapJavaHashMap
- 深入淺出 Locust 實現
- HashMap底層實現原理/HashMap與HashTable區別/HashMap與HashSet區別HashMap
- 【深入淺出ES6】Set\Map
- Hashtable和HashMapHashMap
- HashMap、HashTable、ConcurrentHashMap的區別HashMap
- 深入淺出--梯度下降法及其實現梯度
- 深入淺出 Java 中列舉的實現原理Java
- TreeMap和HashMap的元素比較HashMap
- HashMap與LinkedHashMap型別集合HashMap型別
- 深入 Go 的 Map 使用和實現原理Go
- HashMap、Hashtable、ConcurrentHashMap的原理與區別HashMap
- 深入淺出 Vue 系列 -- 資料劫持實現原理Vue
- 深入淺出FE(十四)深入淺出websocketWeb
- Java 從 Map 到 HashMap 的一步步實現JavaHashMap
- C#中Hashtable和HashMap的區別C#HashMap
- 集合類HashMap,HashTable,ConcurrentHashMap區別?HashMap
- IO多路複用——深入淺出理解select、poll、epoll的實現
- 反射的深入淺出反射
- Map集合中的具體子類TreeMap
- LRU 實現 通過 LinkedHashMapHashMap
- Hashtable/HashMap與key/value為null的關係HashMapNull
- java複習之HashMap和Hashtable的區別JavaHashMap
- 深入淺出換膚相關技術以及如何實現
- 三,TreeMap和HashMap,TreeSet和HashMap的區別以及方法使用上的不同HashMap
- 5、Map集合——HashMapHashMap
- 淺讀-《深入淺出Nodejs》NodeJS
- 深入淺出Seata的AT模式模式
- 深入淺出mongooseGo
- HTTP深入淺出HTTP