JavaSE——集合8:Map接口
目录
一、Map接口实现类的特点
二、Map接口常用方法
三、Map三组遍历方式
四、练习题(重要)
一、Map接口实现类的特点
Map 接口实现类的特点,使用实现类HashMap解析:
- Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
- Map 中的 key 和 value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中
- Map 中的 key 不允许重复,原因和HashSet 一样
- Map 中的 value 可以重复
- Map 的key 可以为 null, value 也可以为null;注意 key 为null,只能有一个,value 为null,可以多个
- 常用String类作为Map的 key
- key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value
public class Map_ {
public static void main(String[] args) {
Map map = new HashMap();
map.put("no1", "张三"); // k-v
map.put("no2", "张无忌"); // k-v
map.put("no1", "张三丰"); // 当有相同的k , 就等价于替换.
map.put("no3", "张三丰"); // k-v
map.put(null, null); // k-v
map.put(null, "abc"); // 等价替换
map.put("no4", null); // k-v
map.put("no5", null); // k-v
map.put(1, "赵敏"); // k-v
map.put(new Object(), "金毛狮王"); // k-v
// 通过get 方法,传入 key ,会返回对应的value
System.out.println(map.get("no2")); // 张无忌
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
// no2=张无忌
// null=abc
// no1=张三丰
// 1=赵敏
// java.lang.Object@5594a1b5=金毛狮王
// no4=null
// no3=张三丰
// no5=null
}
}
8.Map存放数据的key-value示意图,一堆k-v是放在一个HashMap$Node中的,又因为Node实现了Entry接口,也可以说一对k-v就是一个Entry。
原理详解:很重要!!!
掌握了这里,在遍历map集合时,才能知道,使用不同的遍历方式得到的返回值类型。
1. k-v 最后是 HashMap$Node node = newNode(hash, key, value, null);
2. k-v 为了方便遍历,还会 创建 EntrySet 集合 ,该集合存放的元素的类型 Entry,而一个Entry 对象就有k,v EntrySet<Entry<K,V>> 即: transient Set<Map.Entry<K,V>> entrySet;
3. entrySet 中, 定义的类型是 Map.Entry ,但是实际上存放的还是 HashMap$Node
这是因为Node实现了Map.Entry接口,即:static class Node<K,V> implements Map.Entry<K,V>;
当有一个类实现了一个接口,该类的对象实例就可以赋给接口,这里就体现了多态;
所以,Node<K,V> 就可以赋值给Map.Entry<K,V>;
4. 当把 HashMap$Node 对象 "存放"到 entrySet 后,就方便遍历了;
因为 Map.Entry 提供了重要方法:K getKey(); V getValue();
注意:这里不是真正的存放到entrySet中!!! 是多态!!!
public class MapSource_ {
public static void main(String[] args) {
Map map = new HashMap();
map.put("no1", "张三"); // k-v
map.put("no2", "张无忌"); // k-v
map.put(new Car(), new Person()); // k-v
// Set的类型是EntrySet,EntrySet集合中存放的是多个Entry对象,而每个Entry对象里面都有K,V
Set set = map.entrySet();
System.out.println(set.getClass());// HashMap$EntrySet
for (Object obj : set) {
// System.out.println(obj.getClass()); // HashMap$Node
// 为了从 HashMap$Node 取出k-v
// 1. 先做一个向下转型
Map.Entry entry = (Map.Entry) obj;
System.out.println(entry.getKey() + "-" + entry.getValue() );
}
// no2-张无忌
// no1-张三
// com.testdemo.map_.Car@3b6eb2ec-com.testdemo.map_.Person@73f792cf
// Set和Collection只是一个引用
// set1的实际运行类型是KeySet,是Set的一个子类
Set set1 = map.keySet();
System.out.println(set1.getClass());
// class java.util.HashMap$KeySet
// values的实际运行类型是Values,是Collection的一个子类
Collection values = map.values();
System.out.println(values.getClass());
// class java.util.HashMap$Values
}
}
class Car {}
class Person{}
二、Map接口常用方法
- put:添加
- remove:根据键删除映射关系
- get:根据键获取值
- size:获取元素个数
- isEmpty:判断个数是否为0
- clear:清楚
- containsKey:查找键是否存在
public class MapMethod {
public static void main(String[] args) {
Map map = new HashMap();
// put:添加
// key相同,value不同
map.put("梁山伯", new Book("", 100)); // OK
map.put("梁山伯", "祝英台"); // 替换
// key不同,value相同
map.put("林黛玉", "贾宝玉"); // OK
map.put("薛宝钗", "贾宝玉");// OK
// value为null
map.put("张三", null); // OK
// key为null
map.put(null, "李四"); // OK
map.put("jack", "rose");// OK
System.out.println("map=" + map);
// map={null=李四, 张三=null, 薛宝钗=贾宝玉, 梁山伯=祝英台, 林黛玉=贾宝玉, jack=rose}
// remove:根据键删除映射关系
map.remove(null);
System.out.println("map=" + map);
// map={张三=null, 薛宝钗=贾宝玉, 梁山伯=祝英台, 林黛玉=贾宝玉, jack=rose}
// get:根据键获取值
Object val = map.get("jack");
System.out.println("val=" + val);
// val=rose
// size:获取元素个数
System.out.println("k-v=" + map.size());
// k-v=5
// isEmpty:判断个数是否为0
System.out.println(map.isEmpty()); // false
// clear:清除k-v
// map.clear();
// System.out.println("map=" + map); // map={}
// containsKey:查找键是否存在
System.out.println("结果=" + map.containsKey("林黛玉"));
// 结果=true
}
}
class Book {
private String name;
private int num;
public Book(String name, int num) {
this.name = name;
this.num = num;
}
}
三、Map三组遍历方式
Map集合的三组遍历方式分为:遍历所有key;遍历所有value;通过entrySet获取k-v
- keySet:获取所有的键
- entrySet:获取所有关系k-v
- values:获取所有的值
注意:一定要了解Map接口实现类的特点以后再来遍历,知道每次遍历出来时什么数据类型,才知道如何向下转型,在什么时候进行向下转型,而不是机械地记忆这些遍历方式。
public class MapFor {
public static void main(String[] args) {
Map map = new HashMap();
map.put("梁山伯", "祝英台");
map.put("林黛玉", "贾宝玉");
map.put("薛宝钗", "贾宝玉");
map.put("张三", null);
map.put(null, "李四");
map.put("jack", "rose");
// 第一组: 先取出 所有的Key , 再通过Key 取出对应的Value
Set keyset = map.keySet();
// (1) 增强for
System.out.println("-----第一种方式-------");
for (Object key : keyset) {
System.out.println(key + "-" + map.get(key));
}
// null-李四
// 张三-null
// 薛宝钗-贾宝玉
// 梁山伯-祝英台
// 林黛玉-贾宝玉
// jack-rose
// (2) 迭代器
System.out.println("----第二种方式--------");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "-" + map.get(key));
}
// null-李四
// 张三-null
// 薛宝钗-贾宝玉
// 梁山伯-祝英台
// 林黛玉-贾宝玉
// jack-rose
// 第二组: 把所有的values取出
Collection values = map.values();
// 这里可以使用所有的Collections使用的遍历方法
// (1) 增强for
System.out.println("---取出所有的value 增强for----");
for (Object value : values) {
System.out.println(value);
}
// 李四
// null
// 贾宝玉
// 祝英台
// 贾宝玉
// rose
// (2) 迭代器
System.out.println("---取出所有的value 迭代器----");
Iterator iterator2 = values.iterator();
while (iterator2.hasNext()) {
Object value = iterator2.next();
System.out.println(value);
}
// 李四
// null
// 贾宝玉
// 祝英台
// 贾宝玉
// rose
// 第三组: 通过EntrySet 来获取 k-v
Set entrySet = map.entrySet(); // Set<Map.Entry<K, V>> entrySet();
System.out.println("---------第三种方式--------");
// (1) 增强for
System.out.println("----使用EntrySet 的 for增强(第3种)----");
for (Object entry : entrySet) {
// 将entry 向下转型 转成 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
// null-李四
// 张三-null
// 薛宝钗-贾宝玉
// 梁山伯-祝英台
// 林黛玉-贾宝玉
// jack-rose
System.out.println("---------第四种方式--------");
// (2) 迭代器
System.out.println("----使用EntrySet 的 迭代器----");
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {
Object entry = iterator3.next();
// System.out.println(next.getClass());// HashMap$Node -实现-> Map.Entry (getKey,getValue)
// 向下转型 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
// null-李四
// 张三-null
// 薛宝钗-贾宝玉
// 梁山伯-祝英台
// 林黛玉-贾宝玉
// jack-rose
}
}
四、练习题(重要)
该练习题能够充分检验Map遍历原理是否真正掌握:
使用HashMap添加3个员工对象,员工类:姓名、工资、员工id。
要求:键:员工id 值:员工对象 并遍历显示工资>18000的员工
public class MapExercise {
public static void main(String[] args) {
Map map = new HashMap();
Employee employee1 = new Employee("张三", 24000, 1);
Employee employee2 = new Employee("李四", 15000, 2);
Employee employee3 = new Employee("王五", 20000, 3);
map.put(employee1.getId(), employee1);
map.put(employee2.getId(), employee2);
map.put(employee3.getId(), employee3);
// 显示工资>18000的员工
System.out.println("--------第一组:先取出所有的key---------");
Set keySet = map.keySet();
System.out.println("-------方式一:-------");
// 增强for
for (Object key : keySet) {
Employee employee = (Employee) map.get(key);
if (employee.getSalary() > 18000) {
System.out.println(employee);
}
}
System.out.println("-------方式二:-------");
// 迭代器
Iterator iterator = keySet.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
Employee employee = (Employee) map.get(key);
if (employee.getSalary() > 18000) {
System.out.println(employee);
}
}
System.out.println("--------第二组:先取出所有的value---------");
System.out.println("-------方式一:-------");
Collection collection = map.values();
for (Object obj : collection) {
Employee employee = (Employee) obj;
if (employee.getSalary() > 18000) {
System.out.println(employee);
}
}
System.out.println("-------方式二:-------");
// 迭代器
Iterator iterator1 = collection.iterator();
while (iterator1.hasNext()) {
Employee employee = (Employee) iterator1.next();
if (employee.getSalary() > 18000) {
System.out.println(employee);
}
}
System.out.println("--------第三组:使用entrySet---------");
Set entrySet = map.entrySet();
System.out.println("-------方式一:-------");
// 增强for
for (Object entry : entrySet) {
Map.Entry entry1 = (Map.Entry) entry;
Employee employee = (Employee) entry1.getValue();
if (employee.getSalary() > 18000) {
System.out.println(employee);
}
}
System.out.println("-------方式二:-------");
// 迭代器
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
Map.Entry entry = (Map.Entry) iterator2.next();
Employee employee = (Employee) entry.getValue();
if (employee.getSalary() > 18000) {
System.out.println(employee);
}
}
}
}
class Employee {
private String name;
private double salary;
private int id;
public Employee(String name, double salary, int id) {
this.name = name;
this.salary = salary;
this.id = id;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
", id=" + id +
'}';
}
}