方法 | 描述 |
---|---|
V put(K key, V value) | 將指定的值與該映射中的指定鍵相關聯(可選操做)。 |
V remove(Object key) | 若是存在(從可選的操做),從該地圖中刪除一個鍵的映射。 |
V get(Object key) | 返回到指定鍵所映射的值,或 null若是此映射包含該鍵的映射。 |
boolean containsKey(Object key) | 若是此映射包含指定鍵的映射,則返回 true 。 |
Set
|
返回此地圖中包含的鍵的Set視圖。 |
Set<Map.Entry<K,V>> entrySet() | 返回此地圖中包含的映射的Set視圖。 |
內部接口:Entry<K,V>java
做用:當Map集合建立,就會建立一個Entry對象,用來存儲鍵值對。面試
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /** * 測試Map集合的經常使用方法 * add、remove、get、containKey、keySet、entrySet */ public class TestMap { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); // put的返回值是被替代的V,若是原來沒有就是null System.out.println(map.put("1001", "張三")); System.out.println(map.put("1001", "張三丰")); map.put("1002", "李四"); map.put("1003", "王五"); System.out.println(map); // remove返回被刪除的V,Key不存在則返回null System.out.println(map.remove("1005")); System.out.println(map.remove("1003")); System.out.println(map); // get返回key對應的value, 無則null System.out.println(map.get("1002")); System.out.println(map.get("1003")); // containsKey 包含key返回true System.out.println(map.containsKey("1002")); System.out.println(map.containsKey("1003")); System.out.println("遍歷方式1:將全部key取出來存到set集合"); Set<String> keys = map.keySet(); for (String key : keys) { System.out.println("K:"+key+" V:"+map.get(key)); } System.out.println("遍歷方式2:將全部Entry<K,V>對象取出來存到set集合"); for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println(entry.getKey() + "=" + entry.getValue()); } } }
運行結果數組
null 張三 {1003=王五, 1002=李四, 1001=張三丰} null 王五 {1002=李四, 1001=張三丰} 李四 null true false 遍歷方式1:將全部key取出來存到set集合 K:1002 V:李四 K:1001 V:張三丰 遍歷方式2:將全部Entry<K,V>對象取出來存到set集合 1002=李四 1001=張三丰
基於哈希表的實現的Map
接口。 此實現提供了全部可選的Map操做,並容許null
值和null
鍵。安全
底層是哈希表,查詢速度超級快!多線程
JDK8以前:數組+鏈表ide
JDK8以後:數組+鏈表 / 數組+紅黑樹學習
HashMap面試須要更深的理解,深刻底層!測試
目前停留於瞭解原理,掌握運用。this
首先建立一個學生類線程
package map; public class Student{ private int id; private String name; private int age; public Student() { } public Student(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
測試類
package map; import java.util.HashMap; /** * 若以自定義類做鍵存放,必須說明鍵重複的規則 * 實體類重寫hashCode方法和equals方法 * 好比學生類中,同名不必定是同一個對象,同窗號說明是同一個學生 */ public class TestHashMap { public static void main(String[] args) { Student student1 = new Student(1001, "張三", 18); Student student2 = new Student(1002, "李四", 17); Student student3 = new Student(1001, "張三", 19); Student student4 = new Student(1004, "李四", 20); HashMap<Student, String> map = new HashMap<>(); map.put(student1, "第一名"); map.put(student2, "第二名"); map.put(student3, "第三名"); map.put(student4, "第四名"); System.out.println(map); } }
運行結果
{Student{id=1004, name='李四', age=20}=第四名, Student{id=1002, name='李四', age=17}=第二名, Student{id=1001, name='張三', age=18}=第一名, Student{id=1001, name='張三', age=19}=第三名}
此時觀察student1 和 student3 的學號相同,對象重複,爲何還會添加到map中呢?
有提示要重寫Student類的hashCode方法和equals方法。
修改後的Student.java
package map; import java.util.Objects; public class Student{ private int id; private String name; private int age; public Student() { } public Student(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } // ...get/set省略 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return id == student.id; } @Override public int hashCode() { return Objects.hash(id); } }
再次運行測試類的代碼獲得的結果
{Student{id=1001, name='張三', age=18}=第三名, Student{id=1002, name='李四', age=17}=第二名, Student{id=1004, name='李四', age=20}=第四名}
分析:第一次添加1001學生時,value是第一名,再次遇到1001學生,覆蓋了原來的value
更加詳細的學習會寫到另外一篇
哈希表和鏈表實現的Map
接口,具備可預測的迭代次序。有序集合!
public class LinkedHashMap<K,V>extends HashMap<K,V>implements Map<K,V>{}
import java.util.*; public class TestLinkedHashMap { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.put("1001", "張三"); map.put("1002", "李四"); map.put("1003", "王五"); map.put("1004", "趙六"); System.out.println("map的數據無序,取出的結果與存入順序不一致:"); System.out.println(map); System.out.println(); LinkedHashMap<String, String> link = new LinkedHashMap<>(); link.put("1001", "張三"); link.put("1002", "李四"); link.put("1003", "王五"); link.put("1004", "趙六"); System.out.println("在map外層加一層鏈表記錄元素存入的順序:"); System.out.println(link); } }
運行結果
map的數據無序,取出的結果與存入順序不一致: {1004=趙六, 1003=王五, 1002=李四, 1001=張三} 在map外層加一層鏈表記錄元素存入的順序: {1001=張三, 1002=李四, 1003=王五, 1004=趙六}
Hashtable 和 Vector 同樣都是上古級別的集合,在jdk1.2版本以後被更先進的HashMap及ArrayList集合取代。
值得注意的是,Hashtable的子類Properties目前依舊活躍着,它是惟一和IO流結合的集合。
底層都是哈希表,元老級更注重線程安全。
Hashtable
HashMap
import java.util.HashMap; import java.util.Hashtable; public class TestHashtable { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.put(null, null); map.put("A", null); map.put(null, "B"); System.out.println(map); Hashtable<String, String> table = new Hashtable<>(); //table.put(null, null);//NullPointerException //table.put("A", null);//NullPointerException //table.put(null, "B");//NullPointerException System.out.println(table); } }
運行結果
{null=B, A=null} {}
HashMap中以null做爲鍵時,再次添加null的鍵會覆蓋以前的value值。
Hashtable只要涉及到null,就會報空指針異常。
判斷字符串中某個字符出現的次數
import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Scanner; /** * 判斷字符串中某個字符出現的次數 */ public class MapPractice { public static void main(String[] args) { Map<Character, Integer> map = new LinkedHashMap<>(); // Scanner sc = new Scanner(System.in); // String str = sc.nextLine(); String str = "aaabbcdaabb"; char[] chars = str.toCharArray(); for (char ch : chars) { if (map.get(ch) == null) { map.put(ch, 1); } else { int count = map.get(ch); map.put(ch, ++count); } } // 使用linkedHashMap保證從前日後統計的順序 System.out.println(map); } }
鬥地主發牌
import java.util.*; /** * 撲克發牌並按大小排序 */ public class PracticePoker { public static void main(String[] args) { // 存放索引的map,一個索引對應一張牌,按照必定規則定製 Map<Integer, String> map = new HashMap<>(); // 存放牌色♠♥♦♣、數字的列表 List<String> colors = new ArrayList<>(); List<String> numbers = new ArrayList<>(); Collections.addAll(colors, "♠", "♥", "♣", "♦"); Collections.addAll(numbers, "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"); // 創建索引與牌的映射 0-"大王" 1-"小王" 2-"2♠" 3-"2♥" ... int idx = 0; map.put(idx++, "大王"); map.put(idx++, "小王"); for (String number : numbers) { for (String color : colors) { map.put(idx++, number + color); //System.out.print(number + color + " "); } } // 發牌發的是索引,便於比大小 , 由於set是無序的,不能洗牌 Set<Integer> idxSet = map.keySet(); ArrayList<Integer> idxList = new ArrayList<>(idxSet); // System.out.println("洗牌前" + idxList); Collections.shuffle(idxList); // System.out.println("洗牌後" + idxList); // 玩家的牌用列表接收,便於排序 ArrayList<Integer> playA = new ArrayList<>(); ArrayList<Integer> playB = new ArrayList<>(); ArrayList<Integer> playC = new ArrayList<>(); ArrayList<Integer> special = new ArrayList<>(); // 發牌 special.add(idxList.get(0)); special.add(idxList.get(1)); special.add(idxList.get(2)); for (int i = 3; i < idxList.size(); i++) { if (i % 3 == 0) { playA.add(idxList.get(i)); } else if (i % 3 == 1) { playB.add(idxList.get(i)); } else if (i % 3 == 2) { playC.add(idxList.get(i)); } } // 排序 Collections.sort(playA); Collections.sort(playB); Collections.sort(playC); Collections.sort(special); // 看牌 lookPoker("劉德華", playA, map); lookPoker("周潤發", playB, map); lookPoker("周星馳", playC, map); lookPoker("底牌", special, map); } public static void lookPoker(String name, List<Integer> idxList, Map<Integer, String> poker) { System.out.print(name + "的牌爲:"); for (Integer idx : idxList) { System.out.print(poker.get(idx) + " "); } System.out.println(); } }
結果
劉德華的牌爲:2♥ 2♦ A♥ A♣ A♦ K♠ K♦ Q♥ J♠ 10♠ 8♥ 8♦ 7♠ 6♣ 5♣ 4♣ 3♥ 周潤發的牌爲:2♠ 2♣ K♣ Q♠ J♣ J♦ 9♥ 9♦ 8♠ 7♣ 7♦ 6♥ 5♠ 5♥ 4♥ 4♦ 3♠ 周星馳的牌爲:大王 小王 A♠ K♥ Q♣ Q♦ J♥ 10♣ 10♦ 9♠ 8♣ 7♥ 6♠ 6♦ 5♦ 4♠ 3♦ 底牌的牌爲:10♥ 9♣ 3♣