Jakob Jenkov 2015-09-02
Java 的 Map 接口(java.util.Map)可以被泛型化。换句话说,你可以为泛型 Map 实例指定键和值的具体类型。例如:
Map<Integer, String> map = new HashMap<Integer, String>();
这个 Map 现在只能接受 Integer 类型的键和 String 类型的值。
注意:泛型类型检查仅在编译时存在。在运行时,仍有可能通过某些手段将其他类型的对象插入其中,但这是非常不推荐的做法。
访问泛型 Map
向泛型 Map 中添加或获取元素,仍然使用你熟悉的 put() 和 get() 方法:
Map<Integer, String> map = new HashMap<Integer, String>();
Integer key1 = new Integer(123);
String value1 = "value 1";
map.put(key1, value1);
String value1_1 = map.get(key1);
那么,泛型带来了什么不同呢?
- 如果你尝试向上述
Map中插入非Integer键或非String值,编译器会报错。这是一个非常有用的额外类型检查。 - 注意,从
get()方法返回的String对象不需要强制类型转换。因为编译器知道该Map的值类型是String,所以自动进行了类型安全处理。
你还可以利用 Java 5 引入的**自动装箱(autoboxing)**特性,使代码更简洁:
Map<Integer, String> map = new HashMap<Integer, String>();
Integer key1 = 123; // 自动装箱
String value1 = "value 1";
map.put(key1, value1);
// 或者直接写成:
map.put(123, value1);
String value1_1 = map.get(123); // 自动拆箱
遍历泛型 Map
Map 提供了两个可遍历的集合:键的 Set 和 值的 Collection。通常我们会遍历键集,并通过 Map.get() 方法获取对应的值。
以下是两个示例:
使用 Iterator 遍历
Map<Integer, String> map = new HashMap<Integer, String>();
// ... 向 Map 中添加键值对
// 遍历键
Iterator<Integer> keyIterator = map.keySet().iterator();
while (keyIterator.hasNext()) {
Integer aKey = keyIterator.next();
String aValue = map.get(aKey);
}
// 遍历值
Iterator<String> valueIterator = map.values().iterator();
while (valueIterator.hasNext()) {
String aString = valueIterator.next();
}
注意:由于 Map 是泛型化的,编译器知道键是 Integer、值是 String,因此从 iterator.next() 返回的对象无需强制转换。
使用增强 for 循环(for-each)
Map<Integer, String> map = new HashMap<Integer, String>();
// ... 添加键值对
// 遍历键
for (Integer aKey : map.keySet()) {
String aValue = map.get(aKey);
System.out.println("" + aKey + ":" + aValue);
}
// 遍历值
for (String aValue : map.values()) {
System.out.println(aValue);
}
注意:在 for 循环的括号中声明了 Integer 和 String 类型的变量。每次迭代时,该变量都会自动持有当前元素(即当前的 Integer 键或 String 值)。