Map<K,V>集合的特点: K用来限制键的类型,V用来限制值的类型
1.Map集合是以键值对的形式存储数据,每个键值对都有键和值
2.Map集合中的键是唯一的,值是可以重复的,如果键重复了,值就会覆盖
3.根据键取值
Map集合子类:
HashMap:存储数据采用的结构是哈希表结构,所以不能保证键值对存取有序,可以保证键唯一
由哈希表保证键唯一,所以键所属的类需要重写hashCode和equals方法
LinkedHashMap:存储数据采用的结构是链表+哈希表结构,由链表保证键值对存取有序,由哈希表保证键唯一
由哈希表保证键唯一,所以键所属的类需要重写hashCode和equals方法
TreeMap:存储数据采用的是红黑树结构,可以保证键唯一,并且可以对键进行排序
public TreeMap(); 按照默认规则排序
public TreeMap(Comparator<? super K> comparator): 按照指定规则排序
知识点-- Map的常用方法
目标
- 使用Map的常用方法
路径
- 代码演示
讲解
Map接口中定义了很多方法,常用的如下:
public V put(K key, V value)
: 把指定的键与指定的值添加到Map集合中。public V remove(Object key)
: 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。public V get(Object key)
根据指定的键,在Map集合中获取对应的值。public boolean containsKey(Object key)
:判断该集合中是否有此键public boolean containsValue(Object value)
:判断该集合中是否有此值public Set<K> keySet()
: 获取Map集合中所有的键,存储到Set集合中。public Collection<V> values()
: 获取Map集合中所有的值,存储到Set集合中。public Set<Map.Entry<K,V>> entrySet()
: 获取到Map集合中所有的键值对对象的集合(Set集合)。
Map接口的方法演示
public class Test {
public static void main(String[] args) {
/*
Map<K,V>的常用方法:
- public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
- public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
- public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
- public boolean containsKey(Object key):判断该集合中是否有此键
- public boolean containsKey(Object value):判断该集合中是否有此值
- public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
- public Collection<V> values(): 获取Map集合中所有的值,存储到Set集合中。
- public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的 键值对对象 的集合(Set集合)。
键值对对象: Entry<K,V>接口类型来表示
由于Entry<K,V>接口是Map接口的成员内部接口,所以外界要使用的时候,需要这么写:Map.Entry<K,V>
Set<String> 字符串对象 String
Set<Map.Entry<K,V>> 键值对对象 Map.Entry<K,V>
*/
// 创建Map集合,限制键的类型为String,值的类型为String类型
Map<String, String> map = new HashMap<>();
// 往map集合中添加键值对
map.put("黄晓明", "杨颖");
map.put("文章", "马伊琍");
map.put("谢霆锋", "王菲");
System.out.println("map:"+map);// {文章=马伊琍, 谢霆锋=王菲, 黄晓明=杨颖}
// 验证: 键唯一,如果键重复了,值会覆盖
map.put("文章", "姚笛");
System.out.println("map:"+map);// {文章=姚笛, 谢霆锋=王菲, 黄晓明=杨颖}
// 验证: 值可以重复
map.put("李亚鹏", "王菲");
System.out.println("map:"+map);// {文章=姚笛, 谢霆锋=王菲, 李亚鹏=王菲, 黄晓明=杨颖}
// 需求:删除李亚鹏这个键对应的键值对
String removeV = map.remove("李亚鹏");
System.out.println("被删除键的值:"+removeV);// 王菲
System.out.println("map:"+map);// {文章=姚笛, 谢霆锋=王菲, 黄晓明=杨颖}
// 需求: 获取文章这个键对应的值
String value1 = map.get("文章");
System.out.println("value1:"+value1);// 姚笛
// 需求:判断是否有谢霆锋这个键
System.out.println(map.containsKey("谢霆锋"));// true
// 需求:判断是否有李亚鹏这个键
System.out.println(map.containsKey("李亚鹏"));// false
// 需求:判断是否有姚笛这个值
System.out.println(map.containsValue("姚笛"));// true
// 需求:判断是否有马伊琍这个值
System.out.println(map.containsValue("马伊琍"));// false
// 需求:获取map集合中所有的键
Set<String> keys = map.keySet();
System.out.println("所有的键:"+keys);// [文章, 谢霆锋, 黄晓明]
// 需求:获取map集合中所有的值
Collection<String> values = map.values();
System.out.println("所有的值:"+values);// [姚笛, 王菲, 杨颖]
// 需求:获取map集合中所有 键值对对象
Set<Map.Entry<String, String>> entrys = map.entrySet();
System.out.println(entrys);// [文章=姚笛, 谢霆锋=王菲, 黄晓明=杨颖]
}
}
tips:
使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
String putV = map.put("邓超", "孙俪");
System.out.println("putV:"+putV);// null
String putValue = map.put("谢霆锋", "张柏芝");
System.out.println("putValue:"+putValue);// 王菲
知识点–Map的遍历
目标
- 使用Map的遍历
路径
- 方式1:键找值方式
- 方式2:键值对方式
讲解
方式1:键找值方式
通过元素中的键,获取键所对应的值
分析步骤:
- 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:
keyset()
- 遍历键的Set集合,得到每一个键。
- 根据键,获取键所对应的值。方法提示:
get(K key)
public class Test1_方式一 {
public static void main(String[] args) {
/*
根据键找值:
1.获取map集合所有的键 keySet()方法
2.遍历所有的键
3.根据键找值 get(K k)方法
*/
// 创建Map集合,限制键的类型为String,值的类型为String类型
Map<String, String> map = new HashMap<>();
// 往map集合中添加键值对
map.put("黄晓明", "杨颖");
map.put("文章", "马伊琍");
map.put("谢霆锋", "王菲");
// 1.获取map集合所有的键 keySet()方法
Set<String> keys = map.keySet();
// 2.遍历所有的键
for (String key : keys) {
// 3.根据键找值 get(K k)方法
String value = map.get(key);
System.out.println("key:"+key+",value:"+value);
}
}
}
方式2:键值对方式
Entry<K,V>接口:简称Entry项,表示键值对对象,用来封装Map集合中的键值对
Entry<K,V>接口:是Map接口中的内部接口,在外部使用的时候是这样表示: Map.Entry<K,V>
Map集合中提供了一个方法来获取所有键值对对象:
public Set<Map.Entry<K,V>> entrySet()
根据键值对对对象获取键和值:
- public K getKey():获取Entry对象中的键。
- public V getValue():获取Entry对象中的值。
Map遍历方式二:根据键值对对象的方式
1.获取集合中所有键值对对象,以Set集合形式返回。 Set<Map.Entry<K,V>> entrySet()
2.遍历所有键值对对象的集合,得到每一个键值对(Entry)对象。
3.在循环中,可以使用键值对对对象获取键和值 getKey()和getValue()
public class Test2_方式二 {
public static void main(String[] args) {
/*
键值对方式:
1.获取map集合的所有键值对对象 entrySet()方法
2.循环遍历所有的键值对对象
3.根据键值对对象去获取键和值
键值对对象: Entry<K,V>接口类型来表示
由于Entry<K,V>接口是Map接口的成员内部接口,所以外界要使用的时候,需要这么写:Map.Entry<K,V>
Entry<K,V>接口中的方法:
K getKey(); 获取键值对对象的键
V getValue();获取键值对对象的值
*/
// 创建Map集合,限制键的类型为String,值的类型为String类型
Map<String, String> map = new HashMap<>();
// 往map集合中添加键值对
map.put("黄晓明", "杨颖");
map.put("文章", "马伊琍");
map.put("谢霆锋", "王菲");
// 1.获取map集合的所有键值对对象 entrySet()方法
Set<Map.Entry<String, String>> entrys = map.entrySet();
// 2.循环遍历所有的键值对对象
for (Map.Entry<String, String> entry : entrys) {
// 3.根据键值对对象去获取键和值
String key = entry.getKey();
String value = entry.getValue();
System.out.println("key:"+key+",value:"+value);
}
}
}
知识点-- HashMap存储自定义类型
目标
- 使用HashMap存储自定义类型
路径
- 代码演示
讲解
练习:每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。
注意,学生姓名相同并且年龄相同视为同一名学生。
编写学生类:
public class Student {
public String name;// 姓名
public int age;// 年龄
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@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 Test {
public static void main(String[] args) {
/*
练习:每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。
学生作为键, 家庭住址作为值。
注意,学生姓名相同并且年龄相同视为同一名学生。
*/
// 创建HashMap集合,限制键的类型为Student,值的类型为String
HashMap<Student, String> map = new HashMap<>();
// 创建学生对象
Student stu1 = new Student("张三",18);
Student stu2 = new Student("李四",19);
Student stu3 = new Student("王五",17);
Student stu4 = new Student("张三",18);
// 往集合中添加键值对
map.put(stu1, "北京");
map.put(stu2, "上海");
map.put(stu3, "深圳");
map.put(stu4, "广州");
// 循环遍历集合
Set<Student> keys = map.keySet();
for (Student key : keys) {
String value = map.get(key);
System.out.println("key:"+key+",value:"+value);
}
}
}
- 当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法(如果忘记,请回顾HashSet存放自定义对象)。
- 如果要保证map中存放的key和取出的顺序一致,可以使用
java.util.LinkedHashMap
集合来存放。
知识点–LinkedHashMap介绍
目标
- 我们知道HashMap保证成对元素唯一,并且查询速度很快,可是成对元素存放进去是没有顺序的,那么我们要保证有序,还要速度快怎么办呢?
路径
- LinkedHashMap
讲解
- 通过链表结构可以保证元素的存取顺序一致;
- 通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
public class Test {
public static void main(String[] args) {
/*
LinkedHashMap集合特点:键值对存取有序,键唯一,值可以重复,如果键重复了,值就会覆盖
由于是由哈希表保证键唯一,所以如果键是自定义类型的类,那么必须重写hashCode和equals方法
*/
// 创建LinkedHashMap集合,限制键的类型为String,值的类型为String
LinkedHashMap<String, String> map = new LinkedHashMap<>();
// 往集合中添加键值对
map.put("黄晓明", "杨颖");
map.put("文章", "马伊琍");
map.put("谢霆锋", "王菲");
map.put("李亚鹏", "王菲");
map.put("文章", "姚笛");
// 打印集合
System.out.println(map);// {黄晓明=杨颖, 文章=姚笛, 谢霆锋=王菲, 李亚鹏=王菲}
}
}
知识点–TreeMap集合
目标
- 使用TreeMap集合
路径
- TreeMap介绍
- 构造方法
讲解
TreeMap介绍
TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的**键进行排序,排序方式有两种:自然排序和比较器排序;到时使用的是哪种排序,取决于我们在创建对象的时候所使用的构造方法;
构造方法
public TreeMap() 使用自然排序
public TreeMap(Comparator<? super K> comparator) 通过比较器指定规则排序
案例演示
public class Test {
public static void main(String[] args) {
/*
TreeMap集合的特点:可以对键值对进行排序,键唯一,值可以重复,如果键重复了,值就会覆盖
TreeMap集合的构造方法:
public TreeMap() 使用默认规则排序
如果键是自定义类型的类,那么该类需要实现Comparable接口,重写compareTo方法,指定排序规则
public TreeMap(Comparator<? super K> comparator) 通过比较器指定规则排序
*/
// 默认规则排序: 升序
// 创建TreeMap集合,限制键的类型为Integer,值的类型为String
TreeMap<Integer, String> map = new TreeMap<>();
// 往集合中添加键值对
map.put(300, "刘德华");
map.put(100, "张学友");
map.put(200, "郭富城");
map.put(500, "黎明");
map.put(400, "梁朝伟");
map.put(400, "古天乐");
map.put(600, "古天乐");
// 打印集合
System.out.println(map);
System.out.println("=======================================");
// 指定规则排序: 降序
// 创建TreeMap集合,限制键的类型为Integer,值的类型为String
TreeMap<Integer, String> map2 = new TreeMap<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
// 往集合中添加键值对
map2.put(300, "刘德华");
map2.put(100, "张学友");
map2.put(200, "郭富城");
map2.put(500, "黎明");
map2.put(400, "梁朝伟");
map2.put(400, "古天乐");
map2.put(600, "古天乐");
// 打印集合
System.out.println(map2);
}
}
案例-- Map集合练习
需求
- 输入一个字符串中每个字符出现次数。
分析
- 获取一个字符串对象
- 创建一个Map集合,键代表字符,值代表次数。
- 遍历字符串得到每个字符。
- 判断Map中是否有该键。
- 如果没有,第一次出现,存储次数为1;如果有,则说明已经出现过,获取到对应的值进行++,再次存储。
- 打印最终结果
实现
方法介绍
public boolean containKey(Object key)
:判断该集合中是否有此键。
代码:
public class Test {
public static void main(String[] args) {
// 1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = sc.nextLine();
// 2.创建Map集合,限制键的类型为Character,值的类型为Integer
Map<Character, Integer> map = new HashMap<>();
// 3.循环遍历该字符串
for (int i = 0; i < str.length(); i++) {
// 4.在循环中,获取遍历出来的字符
char c = str.charAt(i);
// 5.在循环中,判断该字符在Map集合中是否已经作为了键
if (map.containsKey(c)) {
// 6.如果已经作为了键,那么就取出该键对应的值,然后让该值+1,作为新的值,存储到Map集合中
Integer value = map.get(c);
value++;
map.put(c,value);
} else {
// 6.如果没有作为键,那么该字符作为键,值为1,存储到Map集合中
map.put(c,1);
}
}
// 7.打印map集合的键值对
System.out.println(map);
}
}
第四章 集合的嵌套
- 总述:任何集合内部都可以存储其它任何集合
知识点–集合的嵌套
目标
- 理解集合的嵌套
路径
- List嵌套List
- List嵌套Map
- Map嵌套Map
讲解
List嵌套List
public class Test1 {
public static void main(String[] args) {
/*
集合的嵌套:
- List嵌套List
- List嵌套Map
- Map嵌套Map
结论:任何集合内部都可以存储其它任何集合
*/
// List嵌套List
// 创建一个List集合,限制元素类型为String
List<String> list1 = new ArrayList<>();
// 往集合中添加元素
list1.add("王宝强");
list1.add("贾乃亮");
list1.add("陈羽凡");
// 创建一个List集合,限制元素类型为String
List<String> list2 = new ArrayList<>();
// 往集合中添加元素
list2.add("马蓉");
list2.add("李小璐");
list2.add("白百何");
// 创建一个List集合,限制元素类型为List集合 (List集合中的元素是List集合)
List<List<String>> list = new ArrayList<>();
list.add(list1);
list.add(list2);
// 遍历
for (List<String> e : list) {
for (String name : e) {
System.out.println(name);
}
System.out.println("=============");
}
System.out.println(list);
}
}
List嵌套Map
public class Test2 {
public static void main(String[] args) {
/*
List嵌套Map:
*/
// 创建Map集合对象
Map<String,String> map1 = new HashMap<>();
map1.put("it001","迪丽热巴");
map1.put("it002","古力娜扎");
// 创建Map集合对象
Map<String,String> map2 = new HashMap<>();
map2.put("heima001","蔡徐坤");
map2.put("heima002","李易峰");
// 创建List集合,用来存储以上2个map集合
List<Map<String,String>> list = new ArrayList<>();
list.add(map1);
list.add(map2);
System.out.println(list.size()); // 2
for (Map<String, String> map : list) {
// 遍历获取出来的map集合对象
Set<String> keys = map.keySet();// 获取map集合所有的键
// 根据键找值
for (String key : keys) {
System.out.println(key + ","+ map.get(key));
}
}
}
}
Map嵌套Map
public class Test3_Map嵌套Map {
public static void main(String[] args) {
/*
Map嵌套Map:
*/
// 创建Map集合对象
Map<String, String> map1 = new HashMap<>();
map1.put("it001", "迪丽热巴");
map1.put("it002", "古力娜扎");
// 创建Map集合对象
Map<String, String> map2 = new HashMap<>();
map2.put("heima001", "蔡徐坤");
map2.put("heima002", "李易峰");
// 创建Map集合,把以上2个Map集合作为值存储到这个map集合中
Map<String, Map<String, String>> map = new HashMap<>();
// 往map集合中添加键值对
map.put("itheima", map1);
map.put("itcast", map2);
// 获取map集合所有的键
Set<String> keys = map.keySet();
// 循环遍历所有的键
for (String key : keys) {
// 根据键找值
Map<String, String> stringMap = map.get(key);
//System.out.println(key + ":" + stringMap);
// 获取stringMap集合所有的键
Set<String> keySet = stringMap.keySet();
// 循环遍历所有的键
for (String k : keySet) {
// 根据键找值
String v = stringMap.get(k);
System.out.println(k+"="+v);
}
System.out.println("===================");
}
}
}