Java 集合深入理解(14):Map 概述
終於把 List 常用的幾種容器介紹完了,接下來開始 Map 的相關介紹。
什麼是 Map
Java 中的 Map 介面 是和 Collection 介面 同一等級的集合根介面,它 表示一個鍵值對 (key-value) 的對映。類似數學中 函式 的概念。
數學中的函式:
一個 Map 中,任意一個 key 都有唯一確定的 value 與其對應,這個 key-value 的對映就是 map。
Map 中元素的順序取決於迭代器迭代時的順序,有的實現類保證了元素輸入輸出時的順序,比如說 TreeMap;有的實現類則是無序的,比如 HashMap。
Map 的三個 collection 檢視:
Map 介面提供了三種角度來分析 Map:
- KeySet
- Values
- Entry
1.KeySet
KeySet 是一個 Map 中鍵(key)的集合,以 Set 的形式儲存,不允許重複,因此鍵儲存的物件需要重寫 equals() 和 hashCode() 方法。
在上圖就是儲存 AA, BB, CC, DD… 等鍵的集合。
可以通過 Map.keySet() 方法獲得。
2.Values
Values 是一個 Map 中值 (value) 的集合,以 Collection 的形式儲存,因此可以重複。
在上圖就是儲存 90,90,56,78… 等值的集合。
通過 Map.values() 方法獲得。
3.Entry
Entry 是 Map 介面中的靜態內部介面,表示一個鍵值對的對映,例如上圖中 AA-90 這一組對映關係。
Entry 具有上圖中的方法:
- getKey() , 獲取這組對映中的鍵 key
- getValue() , 獲取這組對映中的值 value
- setValue() , 修改這組對映中的值
- hashCode() , 返回這個 Entry 的雜湊值
- equals() , 對比 key-value 是否相等
通過 Map.entrySet() 方法獲得的是一組 Entry 的集合,儲存在 Set 中,所以 Map 中的 Entry 也不能重複。
public Set<Map.Entry<K,V>> entrySet();
Map 的三種遍歷方式
根據 Map 提供的三種檢視,可以有三種 map 遍歷方式 :
1.使用 keySet 遍歷:
Set set = map.keySet();
for (Object key : set) {
System.out.println(map.get(key));
}
2.使用 values 遍歷:
Collection values = map.values();
Iterator iterator = values.iterator();
while (iterator.hasNext()){
System.out.println("value " + iterator.next());
}
3.使用 Entry 遍歷
Set entrySet = map.entrySet();
for (Object o : entrySet) {
Map.Entry entry = (Map.Entry) o;
System.out.println(entry); //key=value
System.out.println(entry.getKey() + " / " + entry.getValue());
}
Map 的實現類
Map 的實現類主要有 4 種:
- Hashtable
- 古老,執行緒安全
- HashMap
- 速度很快,但沒有順序
- TreeMap
- 有序的,效率比 HashMap 低
- LinkedHashMap
- 結合 HashMap 和 TreeMap 的有點,有序的同時效率也不錯,僅比 HashMap 慢一點
其中後三個的區別很類似 Set 的實現類:
- HashSet
- TreeSet
- LinkedHashSet
Map 的每個實現類都應該實現 2 個構造方法:
- 無參構造方法,用於建立一個空的 map
- 引數是 Map 的構造方法,用於建立一個包含引數內容的新 map
第二種構造方法允許我們複製一個 map。
雖然沒有強制要求,但自定義 Map 實現類時最好都這樣來。
總結
Map 有以下特點:
- 沒有重複的 key
- 每個 key 只能對應一個 value, 多個 key 可以對應一個 value
- key,value 都可以是任何引用型別的資料,包括 null
- Map 取代了古老的 Dictionary 抽象類
注意:
可以使用 Map 作為 Map 的值,但禁止使用 Map 作為 Map 的鍵。因為在這麼複雜的 Map 中,equals() 方法和 hashCode() 比較難定義。
另一方面,你應該儘量避免使用“可變”的類作為 Map 的鍵。如果你將一個物件作為鍵值並儲存在 Map 中,之後又改變了其狀態,那麼 Map 就會產生混亂,你所儲存的值可能丟失。