使用 Map
在 java 集合中,Map 并不在接口 Collection 之中。
接口 Map 的常用实现类有:
-
EnumMap 类
-
HashMap 类
-
TreeMap 类(TreeMap 是接口 SortedMap 的实现类,接口 SortedMap 是 Map 的子接口)
-
Properties 类等
Map是一种键值(key-value)映射表的数据结构,作用就是能高效通过key快速查找value(元素)。
Map 的实现类:HashMap
HashMap是一种通过对key计算hashCode(),通过空间换时间的方式,直接定位到value所在的内部数组的索引,因此,查找效率非常高。
用HashMap来实现根据name查询某个Student的代码如下:
public class MapMain {
public static void main(String[] args){
Student student = new Student("xiao ming",99);
HashMap<String, Student> map = new HashMap<>();
// 将 "xiao ming"与Student 实例映射起来
map.put("xiao ming", student);
// // 通过key查找并返回映射的Student实例
Student target = map.get("xiao ming");
System.out.println(target == student);
System.out.println(target.score);
Student bob = map.get("Bob");
System.out.println(bob);
}
static class Student{ // static 不可或缺
public String name;
public int score;
public Student(String name, int score){
this.name = name;
this.score = score;
}
}
}
通过上述代码可知:Map<K, V>是一种键-值映射表,当我们调用put(K key, V value)方法时,就把key和value做了映射并放入Map。当我们调用V get(K key)时,就可以通过key获取到对应的value。如果key不存在,则返回null。
和List类似,Map也是一个接口,最常用的实现类是HashMap。
始终牢记:Map中不存在重复的key,因为放入相同的key,只会把原有的key-value对应的value给替换掉。
此外,在一个Map中,虽然key不能重复,但value是可以重复的:
Map<String, Integer> map = new HashMap<>();
map.put("apple", 123);
map.put("pear", 123); // ok
遍历 Map
对Map来说,要遍历key可以使用增强for循环遍历Map实例的keySet()方法返回的Set集合,它包含不重复的key的集合:
public static void main(String[] args){
HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 124);
map.put("pear", 345);
map.put("banana", 567);
for (String key:map.keySet()){
Integer value = map.get(key);
System.out.println(key + "=" + value);
}
}
同时遍历key和value可以使用增强for循环遍历Map对象的entrySet()集合,它包含每一个key-value映射:
public static void main(String[] args){
HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 123);
map.put("pear", 456);
map.put("banana", 789);
for (Map.Entry<String, Integer> entry:map.entrySet()){
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key + "=" + value);
}
}
Map和List不同的是,Map存储的是key-value的映射关系,并且,它不保证顺序。
在遍历的时候,遍历的顺序既不一定是put()时放入的key的顺序,也不一定是key的排序顺序。使用Map时,任何依赖顺序的逻辑都是不可靠的。
Map 的实现类 EnumMap
如果作为key的对象是enum类型,那么,还可以使用Java集合库提供的一种EnumMap,它在内部以一个非常紧凑的数组存储value,并且根据enum类型的key直接定位到内部数组的索引,并不需要计算hashCode(),不但效率最高,而且没有额外的空间浪费。
我们以DayOfWeek这个枚举类型为例,为它做一个“翻译”功能:
public class Main {
public static void main(String[] args) {
Map<DayOfWeek, String> map = new EnumMap<>(DayOfWeek.class);
map.put(DayOfWeek.MONDAY, "星期一");
map.put(DayOfWeek.TUESDAY, "星期二");
map.put(DayOfWeek.WEDNESDAY, "星期三");
map.put(DayOfWeek.THURSDAY, "星期四");
map.put(DayOfWeek.FRIDAY, "星期五");
map.put(DayOfWeek.SATURDAY, "星期六");
map.put(DayOfWeek.SUNDAY, "星期日");
System.out.println(map);
System.out.println(map.get(DayOfWeek.MONDAY));
}
}
小结
-
如果Map的key是enum类型,推荐使用EnumMap,既保证速度,也不浪费空间。
-
使用EnumMap的时候,根据面向抽象编程的原则,应持有Map接口。
使用TreeMap
TreeMap 是接口 SortedMap 的实现类,而接口 SortedMap是接口 Map 的子接口。
SortedMap保证遍历时以Key的顺序来进行排序。
例如,放入的Key是"apple"、"pear"、"orange",遍历的顺序一定是"apple"、"orange"、"pear",因为String默认按字母排序:
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap<>();
map.put("orange", 1);
map.put("apple", 2);
map.put("pear", 3);
for (String key : map.keySet()) {
System.out.println(key);
}
// apple, orange, pear
}
}
使用TreeMap时,放入的Key必须实现Comparable接口。
String、Integer这些类已经实现了Comparable接口,因此可以直接作为Key使用。作为Value的对象则没有任何要求。
下图是已经实现了Comparable接口的类:
每天学习一点点,每天进步一点点。