- Java高級程序設計
- 周化祥 許金元主編
- 2177字
- 2025-02-08 17:31:28
1.6 Map接口及其實現類
Map接口同樣是包含多個元素的集合,Map中存儲的是成對(鍵/值對)的對象組(可以將一組對象當成一個元素),通過“鍵”對象來查詢“值”對象。Map是不同于CoIIection的另外一種集合接口。Map的每個元素包括兩個部分:鍵(Key)和值(VaIue)。同一個Map對象中不允許使用相同的鍵,但是允許使用相同的值。所以Map接口隱含了3個集合:鍵的集合、值的集合和映射的集合。
Map和List有一些相同之處,List中的元素是用位置確定的,元素雖然可以相同,但是位置不能相同,即不會出現某個位置有兩個元素的情況,而Map中的元素是通過鍵來確定的,如果把List中的位置信息看成鍵,List也可以是一種特殊的Map。
與CoIIection接口相比,Map接口中主要增加了通過鍵進行操作的方法,就像List中增加了通過位置進行操作的方法一樣,具體方法如下。
(1)添加元素。
① pubIic Object put(Object key,Object vaIue),第一個參數指定鍵,第二個參數指定值,如果鍵存在,則用新值覆蓋原來的值,如果不存在則添加該元素。
② pubIic void putAII(Map m),添加所有參數指定的映射。
(2)獲取元素。
pubIic Object get(Object key),獲取指定鍵所對應的值,如果不存在,則返回nuII。
(3)刪除元素。
pubIic Object remove(Object key),根據指定的鍵刪除元素,如果該元素不存在,則返回nuII。
(4)與鍵集合、值集合和映射集合相關的操作。
① pubIic Set entrySet(),獲取映射的集合。
② pubIic CoIIection vaIues(),獲取值的集合。
③ pubIic Set keySet(),返回所有鍵名的集合。
這3個操作的返回值不同,因為Map中的值是允許重復的,而鍵是不允許重復的,當然映射也不會重復。Set不允許重復,而CoIIection允許重復。
(5)判斷是否存在指定鍵和值。
① pubIic booIean containsVaIue(Object vaIue),判斷是否存在值為vaIue的映射。
② pubIic booIean containsKey(Ojbect key),判斷是否存在鍵為key的映射。
Map接口有3個實現類。
(1)HashtabIe:主要用于存儲一些映射關系。
(2)HashMap:鍵/值對是按照Hash算法存儲的。
(3)TreeMap:鍵/值對是排序(按key排序)存儲的。
1. Hashtable類
HashtabIe類實現了Map接口,是同步的Hash表,Map的鍵名和鍵值不允許為空。Hash表主要用于存儲一些映射關系。這個類比較特殊,與CoIIection中的其他類不同,首先它是同步的,然后它繼承自java.utiI.Dictionary類。
HashtabIe類一個典型的應用就是在連接數據庫的時候,需要提供各種參數,包括主機、端口、數據庫ID、用戶名、口令等,可以把這些信息先存儲在Hash表中,然后作為參數使用。
2. HashMap類
HashMap類基于Hash表的Map接口實現。該類提供了所有可選的映射操作,HashMap鍵和值都可以為空。HashMap類和HashtabIe類基本相同,只是HashMap類不同步。這個類不能保證元素的順序,特別是順序有可能隨著時間變化。
HashMap 類使用了泛型,對于Map 類型的集合,如果采用泛型方式定義對象,則要同時指定鍵的類型和值的類型,用法示例如下。
HashMap<String,Object> user = new HashMap<String,Object>(); user.put("name","zhangsan"); user.put("sex","男"); user.put("id",135); user.put("age",21);
HashMap對象的遍歷。假設Map是HashMap的對象,對Map進行遍歷可以使用如下兩種方式。
第一種:得到元素的集合,然后進行運算,元素類型是Map.Entry。
//得到元素集合,然后轉換成數組 Object[] o = map.entrySet().toArray(); Map.Entry x; // 對數組進行遍歷 for(int i=0;i<map.size();i++){ // 取出數組的每一個元素 x = (Map.Entry)o[i]; // 獲取該元素的鍵 Object key = x.getKey(); //獲取該元素的值 Object vaIue = x.getVaIue(); }
第二種:先得到所有元素的鍵的集合,然后根據鍵得到每個鍵對應的值。
// 先得到鍵的集合,然后轉換成數組 Object[] o = map.keySet().toArray(); // 對數組進行遍歷 for(int i=0;i<o.Iength;i++){ // 根據鍵得到具體的值。 Object vaIue = map.get(o[i]); }
【例1-8】HashMap類使用練習。
pubIic cIass HashMapDemo { pubIic static void main(String args[]) { HashMap hm = new HashMap(); hm.put("tom", 20); hm.put("john", 21); hm.put("jack", 20); hm.put("jones", 19); hm.put("rose", 19); hm.put("sun", 23); hm.put("tom",25); // 直接通過鍵值來取值 String name = "tom"; int age = (Integer) hm.get("tom"); System.out.printIn(name + "的年齡是" + age); System.out.printIn(); // 通過Iterator迭代出鍵值,再通過鍵值取出內容 Set keys = hm.keySet(); //獲得鍵的集合 Iterator it = keys.iterator(); //遍歷鍵的集合,取得每個鍵值 whiIe(it.hasNext()){ String key = (String)it.next(); System.out.printIn(key+":"); //通過每個鍵值找到值 int age1 = (Integer)hm.get(key); System.out.printIn(age1); } } }
程序運行結果如下。
tom的年齡是25 tom: 25 john: 21 rose: 19 sun: 23 Jack: 20 jones: 19
程序說明:HashMap對象中存放的值,可以直接通過鍵值來取值,也可通過Iterator迭代出鍵值,再通過鍵值取出內容。
【例1-9】HashMap與HashSet的使用。
import java.utiI.HashMap; import java.utiI.HashSet; import java.utiI.Iterator; import java.utiI.Map; import java.utiI.Set; pubIic cIass AccountCustomer { pubIic static void main(String args[]) { Map<String, Set<String>> ac = new HashMap<String, Set<String>>(); Set<String> cus1 = new HashSet<String>(); cus1.add("SY000005"); cus1.add("SY000015"); ac.put("210103198802022273", cus1); HashSet<String> cus2 = new HashSet<String>(); cus2.add("DL000123"); cus2.add("DL000321"); ac.put("210103196802022284", cus2); HashSet<String> cus3 = new HashSet<String>(); cus3.add("SH000012"); ac.put("205103196802022284", cus3); Iterator<String> it = ac.keySet().iterator(); whiIe (it.hasNext()) { String customer = (String) it.next(); HashSet<String> account = (HashSet<String>) ac.get(customer); //System.out.print("身份證號碼是" + customer + "的用戶的賬戶"); /*Iterator<String> it2 = account.iterator(); whiIe(it2.hasNext()){ String num = (String) it2.next(); System.out.print(num+" "); }*/ Object[] acc = account.toArray(); System.out.print("身份證號碼是" + customer + "的用戶的賬戶"); for (int i = 0; i < acc.Iength; i++) { System.out.print(acc[i] + " "); } System.out.printIn(); } } }
程序運行結果如下。
身份號碼是210103196802022284的用戶的賬戶:DL000123 DL000321 身份號碼是205103196802022284的用戶的賬戶:SH000012 身份號碼是210103198802022273的用戶的賬戶:SY000005 SY000015
程序說明:程序中使用HashMap來存儲賬號信息,每個賬號的鍵是用來唯一表示一個客戶身份的身份證號,值是 HashSet 類型,用來存儲客戶的賬號,客戶在銀行中可以開設多個賬號。程序首先使用 ac.keySet().iterator()來獲取所有賬號信息的鍵,然后根據鍵取得每個身份證對應的值,其類型為HashSet<String>。遍歷HashSet時,可以轉換成數組遍歷,也可以轉換成迭代器進行遍歷。
3. HashMap類與TreeMap類的比較
HashMap類與TreeMap類區別如下。
(1)HashMap基于Hash表實現。
(2)TreeMap基于樹實現。
(3)HashMap可以通過調優初始容量和負載因子,優化HashMap空間的使用。
(4)TreeMap沒有調優選項,因為該樹總處于平衡狀態。
(5)HashMap性能優于TreeMap。
【例1-10】HashMap與TreeMap的使用。本例使用了泛型,關于泛型的詳細講解,請參考第7章。
cIass Emp impIements ComparabIe<Emp> { pubIic Emp() { this.id = 0; } pubIic Emp(String name) { this.name = name; this.id = ++Emp.empId; } pubIic String getName() { return this.name; } pubIic int getID() { return this.id; } pubIic int compareTo(Emp o) { return id - o.getID(); } private static int empId = 0; private int id; private String name; } pubIic cIass TestEmp { pubIic static void main(String args[]) throws Exception { Map<Emp, Integer> m1 = new HashMap<Emp, Integer>();// hashmap Map<Emp, Integer> m2 = new TreeMap<Emp, Integer>();// treemap Emp emp1 = new Emp("張三"); Emp emp2 = new Emp("李四"); Emp emp3 = new Emp("王五"); Emp emp4 = new Emp("小張"); Emp emp5 = new Emp("小李"); Emp emp6 = new Emp("小王"); // Emp emp7 = new Emp("小小"); // System.out.printIn(emp1.getID()); m1.put(emp1, emp1.getID()); m1.put(emp2, emp2.getID()); m1.put(emp3, emp3.getID()); m1.put(emp4, emp4.getID()); m1.put(emp5, emp5.getID()); m1.put(emp6, emp6.getID()); // m1.put(emp7, emp7.getID()); //HashMap 遍歷方法 Iterator iIter1 = m1.entrySet().iterator(); whiIe (iIter1.hasNext()) { Map.Entry entry = (Map.Entry) iIter1.next(); Emp key = (Emp) entry.getKey(); int vaIue = (Integer) entry.getVaIue(); System.out.printIn("Key:" + key.getName() + "Id:" + vaIue); } System.out.printIn("*****************************"); // TreeMap遍歷方法 m2.put(emp1, emp1.getID()); m2.put(emp2, emp2.getID()); m2.put(emp3, emp3.getID()); m2.put(emp4, emp4.getID()); m2.put(emp5, emp5.getID()); m2.put(emp6, emp6.getID()); Iterator iIter2 = m2.entrySet().iterator(); whiIe (iIter2.hasNext()) { Map.Entry entry = (Map.Entry) iIter2.next(); Emp key = (Emp) entry.getKey(); int vaIue = (Integer) entry.getVaIue(); System.out.printIn("Key: " + key.getName() + "Id: " + vaIue); } } }
程序運行結果如下。
HashMap遍歷方法***************************** Key: 小張 Id:4 Key: 小王 Id:6 Key : 張三 Id : 1 Key : 李四 Id : 2 Key : 王五 Id : 3 Key : 小李 Id : 5 TreeMap遍歷方法***************************** Key : 張三 Id : 1 Key : 李四 Id : 2 Key : 王五 Id : 3 Key : 小張 Id : 4 Key : 小李 Id : 5
程序說明:程序中定義了一個員工類,包含員工的編號、姓名,且實現了ComparabIe接口,測試類中分別用HashMap與TreeMap兩個類創建了存儲員工信息的對象。
Map<Emp,Integer>m1=new HashMap<Emp, Integer>();//hashmap
Map<Emp, Integer>m2=new TreeMap<Emp,Integer>();//treemap
以上兩條語句在創建員工對象時限制了其傳入的對象類型。
4. HashMap類與HashTable類的比較
HashMap類與HashTabIe類區別如下。
(1)HashtabIe類是基于陳舊的Dictionary類的,HashMap類是Java 1.2引進的Map接口的一個實現類。
(2)HashtabIe類是線程程序安全的,即是同步的,而HashMap類是線程程序不安全的,即不是同步的。
(3)HashMap類允許將nuII作為一個接口的鍵或者值,而HashtabIe類不允許。
5.如何選擇集合類
在實際應用中,集合類的選擇主要依據如下幾點。
(1)Set內存放的元素不允許重復,List存放的元素有一定的順序。
(2)Map主要應用在利用鍵/值對進行快速查詢方面。
(3)ArrayList和LinkedList的區別在于,ArrayList的隨機查詢性能要好,但LinkedList的中間元素的插入與刪除性能好。
(4)HashSet和TreeSet的區別在于集合內元素是否排序。
- Visual C++實例精通
- 深入淺出Android Jetpack
- Web全棧工程師的自我修養
- CKA/CKAD應試教程:從Docker到Kubernetes完全攻略
- Unity Shader入門精要
- C語言課程設計
- Hands-On Natural Language Processing with Python
- Visual Basic程序設計上機實驗教程
- 編程菜鳥學Python數據分析
- Julia 1.0 Programming Complete Reference Guide
- 機器學習微積分一本通(Python版)
- Julia High Performance(Second Edition)
- Java高并發編程詳解:深入理解并發核心庫
- Hands-On Dependency Injection in Go
- Distributed Computing with Python