深入理解集合框架層次結構(篇二)
本篇我們來談對映(Map)
Map
對映資料結構是用來儲存具有對映關係的資料,當要檢視一個元素時,需要查詢元素的精確副本。因此Map集合裡存放著兩組值key(鍵)和value(值)。其中key值唯一,不能重複,value值可重複。Java類庫為對映提供了兩個通用實現:HashMap(雜湊對映)和TreeMap(樹對映),這兩個類都實現了Map介面。
Map是無序的,(這裡的有序和無序不是指集合中的排序,而是是否按照元素新增的順序來儲存物件。)它的儲存結構是雜湊表<key,value>鍵值對,map中插入元素是根據key計算出的雜湊值來儲存元素的,因此他不是按照元素的新增順序來儲存物件的,所以Map是無序的。它的實現類有:HashMap、TableMap和TreeMap。(LinkedHashMap是有序的)
應該選擇雜湊對映還是樹對映呢?
HashMap(雜湊對映):
HashMap 的例項有兩個引數影響其效能:“初始容量” 和 “載入因子”。容量 是雜湊表中桶的數量,初始容量 只是雜湊表在建立時的容量。載入因子 是雜湊表在其容量自動增加之前可以達到多滿的一種尺度。當雜湊表中的條目數超出了載入因子與當前容量的乘積時,則要對該雜湊表進行 rehash 操作(即重建內部資料結構),從而雜湊表將具有大約兩倍的桶數。
- HashMap基於雜湊散列表實現,隨機儲存,無序。
- 無論對於主鍵還是值都允許存為"null",只不過對於主鍵而言要求唯一性,所以key中最多存一個"null".
- HashMap 執行緒不安全,同一時間允許多個執行緒同時進行操作,效率相對較高,但是可能會出現併發錯誤.
HashMap對外提供的常見訪問介面:
- put () ----HashMap物件可通過put()將對映關係資料(key--value)新增到HashMap中。
- isEmpty() ----判斷是否為空
- get() ----獲取key對應的value值
- containsKey ----判斷HashMap是否包含key
- containsvalue ----判斷HashMap是否包含value元素
- putAll() ----將具有多個對映關係資料的全部元素新增到HashMap中
- remove() ----刪除鍵值為key的value值
- clear() ----清空HashMap,它是通過將所有的元素設為null來實現的。
- enrtrySet() ----返回“HashMap中所有Entry的集合”,它是一個集合。
- keySet() ----返回一個Set介面。
HashMap遍歷方式:
- 遍歷HashMap“鍵”集合:
keySet() ----根據keySet()獲取HashMap的“鍵”的Set集合,要想得到“value”,必須先得到key,再通過get(key)得到value(value依賴key)。
- 遍歷HashMap“值”集合:
values() ----根據values()獲取HashMap的“值”集合,再通過Iterator迭代器Next()得到值。
- 遍歷HashMap“鍵值對”集合:
entrySet() ----根據entrySet()獲取HashMap的“鍵值對”的Set集合,可通過get(key)和get(value)分別可直接得到兩者的值(key和value不依賴)。
例:
package net.csdn.qf.homework;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
/**
* @author 北冥有熊
* 2018年11月5日
*/
public class Test01 {
public static void main(String[] args) {
HashMap<String, String> hm = new HashMap<String,String>();
hm.put("00001", "張三");
hm.put("00002", "李四");
hm.put("00018", "王麻子");
hm.put("00009", "趙武");
System.out.println("=============="+hm); //無序輸出
//KeySet遍歷
Set<String> keySet = hm.keySet();//根據keySet()獲取HashMap的“鍵”的Set集合。
//通過Iterator迭代器開始遍歷“第一步”得到的集合。
Iterator<String> iterator = keySet.iterator();
System.out.println("通過keySet遍歷:");//
while(iterator.hasNext()) {
String key = iterator.next(); //得到鍵
String value = hm.get(key); //通過鍵得到值
System.out.println(key+":"+value);
}
//entrySet遍歷
Set<Entry<String, String>> entrySet = hm.entrySet();//根據entrySet()
//獲取HashMap的“鍵值對”的Set集合
//通過Iterator迭代器開始遍歷“第一步”得到的集合。
Iterator<Entry<String, String>> iterator2 = entrySet.iterator();
System.out.println("通過entrySet遍歷:");
while(iterator2.hasNext()) {
Entry<String, String> entry = iterator2.next();//得到下一個
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+":"+value);
}
//values遍歷值
Collection<String> c = hm.values();
Iterator<String> iterator3 = c.iterator();
System.out.println("通過values遍歷:");
while (iterator3.hasNext()) {
String value = iterator3.next();
System.out.println(value);
}
}
}
TreeMap(樹對映):
TreeMap是一個鍵值唯一且有序的集合,底層實現基於“紅黑樹”。(紅黑樹:根節點是黑色,黑色的子節點必然是紅色,從根節點到葉子節點含有的黑色數量是一致的。有關紅黑樹的實現原理參考https://www.cnblogs.com/CarpenterLee/p/5503882.html)。
HashMap 執行緒不安全,同一時間允許多個執行緒同時進行操作,效率相對較高,但是可能會出現併發錯誤.
由於TreeMap是有序的,故有特有方法時hashMap沒有的。比如:
- firstEntry() ----返回一個與該圖的最小金鑰相關的鍵值對映,或
null
如果Map是空的。 - firstKey() ----返回當前在該Map中的第一個(最低)鍵。
更多方法參見API
TreeMap遍歷方式:
- 遍歷HashMap“鍵”集合:
keySet() ----根據keySet()獲取HashMap的“鍵”的Set集合,要想得到“value”,必須先得到key,再通過get(key)得到value(value依賴key)。
- 遍歷HashMap“值”集合:
values() ----根據values()獲取HashMap的“值”集合,再通過Iterator迭代器Next()得到值。
- 遍歷HashMap“鍵值對”集合:
entrySet() ----根據entrySet()獲取HashMap的“鍵值對”的Set集合,可通過get(key)和get(value)分別可直接得到兩者的值(key和value不依賴)。
例:
package net.csdn.qf.test;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class Test06 {
public static void main(String[] args) {
TreeMap<String, Integer> aMap = new TreeMap<String,Integer>();
aMap.put("AA", 18);
aMap.put("BB", 9);
aMap.put("CC", 100);
System.out.println(aMap);
//keySet遍歷
Set<String> keySet = aMap.keySet();
Iterator<String> iterator = keySet.iterator();
System.out.println("keySet遍歷");
while (iterator.hasNext()) {
String key = iterator.next();
Integer value = aMap.get(key);
System.out.println(key+":"+value);
}
//entrySet遍歷
Set<Entry<String, Integer>> entrySet = aMap.entrySet();
Iterator<Entry<String, Integer>> iterator2 = entrySet.iterator();
System.out.println("entrySet遍歷");
while (iterator2.hasNext()) {
Entry<String, Integer> nextEntry = iterator2.next();
String key = nextEntry.getKey();
Integer value = nextEntry.getValue();
System.out.println(key+":"+value);
}
//value遍歷
Collection<Integer> values = aMap.values();
Iterator<Integer> iterator3 = values.iterator();
System.out.println("value遍歷");
while (iterator3.hasNext()) {
Integer value = iterator3.next();
System.out.println(value);
}
}
}
更多底層原理持續更新中。。。