JavaSE——集合7: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-vmap.put("no2", "张无忌"); // k-vmap.put("no1", "张三丰"); // 当有相同的k , 就等价于替换.map.put("no3", "张三丰"); // k-vmap.put(null, null); // k-vmap.put(null, "abc"); // 等价替换map.put("no4", null); // k-vmap.put("no5", null); // k-vmap.put(1, "赵敏"); // k-vmap.put(new Object(), "金毛狮王"); // k-v// 通过get 方法,传入 key ,会返回对应的valueSystem.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-vmap.put("no2", "张无忌"); // k-vmap.put(new Car(), new Person()); // k-v// Set的类型是EntrySet,EntrySet集合中存放的是多个Entry对象,而每个Entry对象里面都有K,VSet set = map.entrySet();System.out.println(set.getClass());// HashMap$EntrySetfor (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)); // OKmap.put("梁山伯", "祝英台"); // 替换// key不同,value相同map.put("林黛玉", "贾宝玉"); // OKmap.put("薛宝钗", "贾宝玉");// OK// value为nullmap.put("张三", null); // OK// key为nullmap.put(null, "李四"); // OKmap.put("jack", "rose");// OKSystem.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:判断个数是否为0System.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 取出对应的ValueSet keyset = map.keySet();// (1) 增强forSystem.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) 增强forSystem.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-vSet entrySet = map.entrySet(); // Set<Map.Entry<K, V>> entrySet();System.out.println("---------第三种方式--------");// (1) 增强forSystem.out.println("----使用EntrySet 的 for增强(第3种)----");for (Object entry : entrySet) {// 将entry 向下转型 转成 Map.EntryMap.Entry m = (Map.Entry) entry;System.out.println(m.getKey() + "-" + m.getValue());}// null-李四// 张三-null// 薛宝钗-贾宝玉// 梁山伯-祝英台// 林黛玉-贾宝玉// jack-roseSystem.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.EntryMap.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("-------方式一:-------");// 增强forfor (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("-------方式一:-------");// 增强forfor (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;}@Overridepublic String toString() {return "Employee{" +"name='" + name + '\'' +", salary=" + salary +", id=" + id +'}';}
}