四十、Map集合
1、概述
java.util.Map<K,V> 集合,裡面儲存的資料是成對存在的,稱之為雙列集合。儲存的資料,我們稱為鍵值對。 之前所學的Collection集合中元素單個單個存在的,稱為單列集合。
K:鍵的資料型別;V:值的資料型別
- 鍵不能重複,值可以重複
- 鍵和值是一一對應的,通過鍵可以找到對應的值
- (鍵 + 值)一起是一個整體,我們稱之為 “鍵值對” 或者 “鍵值對物件” ,在Java中叫做 “Entry物件”
2、Map實現類
HashMap:
此前的HashSet底層實現就是HashMap完成的,HashSet儲存的元素其實就是HashMap集合中儲存的鍵,底層結構是雜湊表結構,具有鍵唯一,無序,特點。
LinkedHashMap:
底層結構是有連結串列和雜湊表結構,去重,有序
TreeMap:
底層是有紅黑樹,去重,通過鍵進行排序
3、Map中常用方法
方法 | 描述 |
---|---|
public V put(K key, V value) |
把指定的鍵與指定的值新增到Map集合中。也可以做修改操作 |
public V remove(Object key) |
把指定的鍵 所對應的鍵值對元素 在Map集合中刪除,返回被刪除元素的值。 |
public V get(Object key) |
根據指定的鍵,在Map集合中獲取對應的值。 |
public Set<K> keySet() |
獲取Map集合中所有的鍵,儲存到 Set 集合中。 |
Collection<V> values() |
獲取Map集合中所有的值,儲存到 Collection 集合中。 |
public Set<Map.Entry<K,V>> entrySet() |
獲取到Map集合中所有的鍵值對物件的集合(Set集合)。 |
public boolean containKey(Object key) |
判斷該集合中是否有此 key 鍵。 |
public boolean containValue(Object value) |
判斷該集合中是否有此 value 值。 |
4、Map集合遍歷
Map集合既不能使用索引來遍歷,也不能使用迭代器遍歷,如果要進行對Map集合遍歷,可以有兩種方式:
-
獲取健集合 , 拿到每一個鍵 , 在通過鍵找到對應值
-
獲取鍵值對物件集合,拿到每一個鍵值對物件 , 在獲取鍵和值
遍歷一:鍵找值方式
操作步驟:
- 獲取Map中所有的鍵,由於鍵是唯一的,所以返回一個Set集合儲存所有的鍵。方法提示:
keyset()
- 遍歷鍵的Set集合,得到每一個鍵。
- 根據鍵,獲取鍵所對應的值。方法提示:
get(K key)
遍歷圖解:
遍歷二:鍵值對物件遍歷
即通過集合中每個鍵值對(Entry)物件,獲取鍵值對(Entry)物件中的鍵與值
操作步驟:
-
獲取Map結合中,所有的鍵值對(Entry)物件,以Set集合形式返回。使用方法entrySet()。
public Set<Map.Entry<K,V>> entrySet()
-
遍歷包含鍵值對(Entry)物件的Set集合,得到每一個鍵值對(Entry)物件
-
通過鍵值對(Entry)物件,獲取Entry物件中的鍵與值。使用方法getKey() getValue()
public K getKey()
public V getValue()
遍歷圖解:
tips:Map集合不能直接使用迭代器或者foreach進行遍歷。但是轉成Set之後就可以使用了。
5、HashMap儲存自定義型別
練習:每位學生(姓名,年齡)都有自己的家庭住址。那麼,既然有對應關係,則將學生物件和家庭住址儲存到map集合中。學生作為鍵, 家庭住址作為值。
【學生類】
public class Student {
private String name;
private int 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 age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
【測試類】
public class HashMapTest {
public static void main(String[] args) {
//1,建立Hashmap集合物件。
Map<Student,String> map = new HashMap<Student,String>();
//2,新增元素。
map.put(new Student("lisi",28), "上海");
map.put(new Student("wangwu",22), "北京");
map.put(new Student("wangwu",22), "南京");
//3,取出元素。鍵找值方式
Set<Student> keySet = map.keySet();
for(Student key: keySet){
String value = map.get(key);
System.out.println(key.toString()+"....."+value);
}
}
}
- 當給HashMap中存放自定義物件時,如果自定義物件作為key存在,這時要保證物件唯一,必須複寫物件的hashCode和equals方法(如果忘記,請回顧HashSet存放自定義物件)。
- 如果要保證map中存放的key和取出的順序一致,可以使用
java.util.LinkedHashMap
集合來存放。
6、LinkedHashMap
我們知道HashMap保證成對元素唯一,並且查詢速度很快,可是成對元素存放進去是沒有順序的,那麼我們要保證有序,還要速度快怎麼辦呢?
在HashMap下面有一個子類LinkedHashMap,它是連結串列和雜湊表組合的一個數據儲存結構。
程式碼體現:
public class LinkedHashMapDemo {
public static void main(String[] args) {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
map.put("鄧超", "孫儷");
map.put("李晨", "范冰冰");
map.put("劉德華", "朱麗倩");
Set<Entry<String, String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
}
/*
鄧超 孫儷
李晨 范冰冰
劉德華 朱麗倩
*/
7、TreeMap集合
7.1 概述
TreeMap集合和Map相比沒有特有的功能,底層的資料結構是紅黑樹;可以對元素的鍵進行排序,排序方式有兩種:自然排序和比較器排序;到時使用的是哪種排序,取決於我們在建立物件的時候所使用的構造方法;
public TreeMap()
:預設使用自然排序
public TreeMap(Comparator<? super K> comparator)
Comparator比較器排序
7.2 自然排序
public static void main(String[] args) {
TreeMap<Integer, String> map = new TreeMap<Integer, String>();
map.put(1,"張三");
map.put(4,"趙六");
map.put(3,"王五");
map.put(6,"酒八");
map.put(5,"老七");
map.put(2,"李四");
System.out.println(map);
}
控制檯的輸出結果為:
{1=張三, 2=李四, 3=王五, 4=趙六, 5=老七, 6=酒八}
7.3 比較器排序
需求:
- 建立一個TreeMap集合,鍵是學生物件(Student),值是居住地 (String)。儲存多個元素,並遍歷。
- 要求按照學生的年齡進行升序排序,如果年齡相同,比較姓名的首字母升序, 如果年齡和姓名都是相同,認為是同一個元素;
實現:
為了保證age和name相同的物件是同一個,Student類必須重寫hashCode和equals方法
【Student類】
public class Student {
private int age;
private String name;
//省略get/set..
public Student() {}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
【測試類】
public static void main(String[] args) {
TreeMap<Student, String> map = new TreeMap<Student, String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//先按照年齡升序
int result = o1.getAge() - o2.getAge();
if (result == 0) {
//年齡相同,則按照名字的首字母升序
return o1.getName().charAt(0) - o2.getName().charAt(0);
} else {
//年齡不同,直接返回結果
return result;
}
}
});
map.put(new Student(30, "jack"), "深圳");
map.put(new Student(10, "rose"), "北京");
map.put(new Student(20, "tom"), "上海");
map.put(new Student(10, "marry"), "南京");
map.put(new Student(30, "lucy"), "廣州");
System.out.println(map);
}
/*
控制檯的輸出結果為:
{
Student{age=10, name='marry'}=南京,
Student{age=10, name='rose'}=北京,
Student{age=20, name='tom'}=上海,
Student{age=30, name='jack'}=深圳,
Student{age=30, name='lucy'}=廣州
}
*/