文章目录
学习日记(集合内容之 Map 集合体系详述)
- Map 集合是一种双列集合,每个元素包含两个数据,也被称为”键值对集合“。
- Map 集合非常适合做购物车这样的业务场景。
- Map 集合体系如下:
一、Map 集合特点
特点:
- Map 集合的特点都是由键决定的,键是无序、不重复、无索引的,值没有要求(可以重复)。
- Map 集合后面重复的键对应的值会覆盖前面重复键的值。
- Map 集合的键值对都可以为 null。
二、常用 API
方法名 | 说明 |
---|---|
put(K key, V value) | 添加键值对 |
get(Object key) | 根据键获取对应的值 |
remove(Object key) | 根据键删除整个元素,返回删除元素的值 |
boolean containsKey(Object key) | 判断是否包含某个键 |
boolean containsValue(Object value) | 判断是否包含某个值 |
Set keySet() | 获取全部键的集合,返回集合为 Set 集合 |
Collection values() | 获取全部值的集合,返回集合为 Collection 集合 |
int size() | 集合的大小 |
void putAll(Map<? extends K, ? extends V> m) | 合并其他集合 |
boolean isEmpty() | 判断集合是否为空 |
void clear() | 清空集合 |
注意:
- 获取全部键的集合时,返回集合为 Set 集合(无序、不重复、无索引)。
- 获取全部值的集合时,返回集合为 Collection 集合,如果值有重复,不会去掉。
- 集合的大小指键值对的数目。
三、遍历
遍历方式有三种:键找值(建议)、键值对、Lambda 表达式。
1. 键找值
步骤:
- 先获取 Map 集合中的全部键的 Set 集合;
- 遍历 Set 集合,然后通过 get 方法通过键提取对应的值。
2. 键值对
若使用 foreach 遍历 Map 集合,但是 Map 集合中的键值对元素是没有类型的,所以不能用 foreach 直接遍历集合。因此,可以先调用 Map 集合中的 entrySet 方法将 Map 集合中的键值对元素转化为键值对实体类型,然后就可以用 foreach 直接遍历集合。
步骤:
- 先把 Map 集合转换为 Set 集合,这样 Set 集合中每个元素都是键值对实体类型;
- 使用 foreach 遍历 Set 集合,然后通过 getKey 和 getValue 方法提取键和值。
方法名 | 说明 |
---|---|
Set<Map.Entry<K, V>> entrySet() | 将 Map 集合中的键值对元素转化为键值对实体类型,存入到 Set 集合中 |
getKey() | 通过键值对实体类型的对象调用,获取键 |
getValue() | 通过键值对实体类型的对象调用,获取值 |
3. Lambda 表达式
Map 集合结合 Lambda 表达式遍历的 API:default void forEach(BiConsumer<? super K, ? super V> action)
。
分析
4. 案例
需求:一个班级 80 个学生,现在需要投票,有 A、B、C、D 四个选项,每个同学只能投一个,统计每个选项的人数。
思路:定义一个数组存放 80 个学生的选择 -> 定义一个 Map 集合存储最终统计的结果 -> 遍历学生的选择,看 Map 集合中是否存在键,若存在,则对应的值加 1;否则,存入该键,值为 1。
拓展:一个班级 80 个学生,现在需要投票,有若干选项,每个同学只能投一个,统计每个选项的人数。
package com.residue.Map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo04 {
public static void main(String[] args) {
//需求:一个班级 80 个学生,现在需要投票,有若干选项,每个同学只能投一个,统计每个选项的人数。
String[] allVotes = {"A", "B", "C", "D", "A", "E", "B", "C", "D", "A",
"X", "K", "C", "D", "A", "A", "Y", "C", "R", "X",
"A", "B", "C", "D", "A", "A", "B", "Z", "D", "A",
"A", "H", "J", "D", "Y", "T", "B", "Y", "T", "A",
"A", "B", "C", "F", "A", "A", "B", "C", "H", "K",
"A", "B", "C", "D", "A", "A", "B", "C", "D", "A",
"X", "B", "T", "D", "Z", "A", "B", "G", "D", "A",
"A", "B", "C", "D", "A", "A", "Z", "C", "D", "A"};
Map<String, Integer> result = new HashMap<>();
for (int i = 0; i < allVotes.length; i++) {
String vote = allVotes[i];
if (result.containsKey(vote)) {
result.put(vote, result.get(vote) + 1);
} else {
result.put(vote, 1);
}
}
Set<String> votes = result.keySet();
for (String vote : votes) {
Integer nums = result.get(vote);
System.out.println("选 " + vote + " 的人数为:" + nums);
}
}
}
四、实现类 HashMap 集合
特点:由键决定,无序、不重复、无索引。
方法:用 Map 中的 API。
底层原理:HashMap 和 HashSet 的底层原理一模一样,都是哈希表结构,因此增删改查的性能都较好,只不过 HashMap 的每个元素包含两个值而已。
自定义类型保证键的唯一:依赖 hashCode 和 equals 方法,所以自定义类型需要重写这两个方法。
注意:实际上,Set 系列集合的底层就是 Map 实现的,只是 Set 集合中的元素只要键数据,不要值数据而已。
五、实现类 LinkedHashMap 集合
特点:由键决定,有序(保证存储和取出的元素顺序一致)、不重复、无索引。
原理:底层数据结构依然是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序。
六、实现类 TreeMap 集合
特点:由键决定,可排序(一定要排序,只能对键排序,可以默认升序排序,也可以自定义排序规则)、不重复、无索引。
排序规则(两种):键的类实现 Comparable 接口,重写比较规则;集合自定义 Comparator 比较器对象,重写比较规则。
原理:TreeMap 集合和 TreeSet 集合的底层原理一样。
第一种排序
第二种排序
七、集合的嵌套
案例再拓展:有 3 个学生,现在需要投票,有 A、B、C、D 等多个选项,每个同学可以投多个,统计每个选项的票数。
package com.residue.Map;
import java.util.*;
public class MapDemo07 {
public static void main(String[] args) {
//有 3 个学生,现在需要投票,有 A、B、C、D 等多个选项,每个同学可以投多个,统计每个选项的票数。
//定义一个 Map 集合,存储每个学生的选择,如:Sun3285=[A, B, C]
Map<String, List<String>> select = new HashMap<>();
List<String> list1 = new ArrayList<>();
Collections.addAll(list1, "A", "B", "F");
select.put("Sun3285", list1); //第一个学生
List<String> list2 = new ArrayList<>();
Collections.addAll(list2, "D", "E");
select.put("Sun4399", list2); //第二个学生
List<String> list3 = new ArrayList<>();
Collections.addAll(list3, "B", "C");
select.put("Sun7849", list3); //第三个学生
System.out.println(select);
System.out.println("===================================");
//定义一个 Map 集合,统计每个选项的人数,如:A=2
Map<String, Integer> result = new HashMap<>();
Collection<List<String>> selects = select.values();
System.out.println(selects);
//把选项都存储到 list 集合中
List<String> list = new ArrayList<>();
for (List<String> strings : selects) {
System.out.println(strings);
for (String string : strings) {
list.add(string);
}
}
System.out.println(list);
//统计选项
for (String s : list) {
if (result.containsKey(s)) {
result.put(s, result.get(s) + 1);
} else {
result.put(s, 1);
}
}
System.out.println(result);
}
}
八、不可变集合
-
不可变集合就是不可被修改的集合,集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变,否则报错。
-
不可变集合创建的原因:想让集合中的数据在后续操作中不被修改,或者集合对象在被不可信的库调用时,不可变的形式是安全的。
-
创建不可变集合:调用 of 方法,如:
List<Integer> lists = List.of(1, 2, 3, 4, 5, 6, 7);
或Map<String, Integer> map1 = Map.of("Sun3285", 1, "Sun3271", 2);
。
集合类型 | 方法 | 说明 |
---|---|---|
List | of() | 静态方法,通过类直接调用,创建一个不可变的 List 集合 |
Set | of() | 静态方法,通过类直接调用,创建一个不可变的 Set 集合 |
Map | of() | 静态方法,通过类直接调用,创建一个不可变的 Map 集合 |
注意:
Set<Integer> set1 = Set.of(1, 2, 3, 2, 1);
会报错,原因:出现重复元素,不能自动去除。
注意:
- 选中某几行代码快捷键:
Shift + 方向键
。 - 选中某几行代码并上下移动快捷键:
Shift + Alt + 方向键
。