Map集合
特點
- 雙列集合<K,V>
- Key 和 Value一一對應
- K不允許重復,V可以重復
- K,V的資料型別可以相同,也可不同
常用方法
| 方法 | 描述 |
|---|---|
| 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>
作用:當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=張三豐
HashMap(重點)
基于哈希表的實作的Map介面, 此實作提供了所有可選的Map操作,并允許null值和null鍵,
底層原理
底層是哈希表,查詢速度超級快!
JDK8之前:陣列+鏈表
JDK8之后:陣列+鏈表 / 陣列+紅黑樹
HashMap面試需要更深的理解,深入底層!
目前停留于了解原理,掌握運用,
測驗代碼
存盤自定義物件
首先創建一個學生類
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
深入理解HashMap
更加詳細的學習會寫到另一篇
LinkedHashMap
哈希表和鏈表實作的Map介面,具有可預測的迭代次序,有序集合!
public class LinkedHashMap<K,V>extends HashMap<K,V>implements Map<K,V>{}
底層原理
- 哈希表 → 繼承自HashMap
- 鏈表 → 記錄元素順序
測驗代碼
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
Hashtable 和 Vector 一樣都是上古級別的集合,在jdk1.2版本之后被更先進的HashMap及ArrayList集合取代,
值得注意的是,Hashtable的子類Properties目前依舊活躍著,它是唯一和IO流結合的集合,
Hashtable 與 HashMap 的區別
底層都是哈希表,元老級更注重執行緒安全,
Hashtable
- 執行緒安全—>單執行緒集合—>速度慢
- 不能存盤 null ,K,V都不可以
HashMap
- 執行緒不安全—>多執行緒集合—>速度快
- 可以存盤 null
- K 只能存盤一個 null ,保證K的唯一性
- V 可以存盤任意個 null
測驗代碼
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?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/147647.html
標籤:Java
