Map 中存放的是键值对。由于Map是按键索引的,因此 key 是不可重复的。但 value 可以重复。
Map 的常用实现类有,HashMap 、Hashtable 和 TreeMap 。其中 TreeMap 和 TreeSet 很相似,它实现了 SortedMap 接口, SortedMap 继承自 Map 接口。看看 API 会发现 HashMap 和 Hashtable 的方法很相近,构造方法甚至是一样的。我们以前见过几个这样的相似类,比如, StringBuilder 和 StringBuffer 、 ArrayList 和 Vector 。 HashMap 和 Hashtable 也和它们一样。 HashMap 是非线程安全的,而 Hashtable 是线程安全的。但它们的区别不只是这些:
HashMap 和 Hashtable 的共同之处:
1、它们都实现了 Map 接口。
2、它们都是哈希表的实现。
HashMap 和 Hashtable 的区别:
1、Hashtable 继承自 Dictionary 类,而 HashMap 继承自 AbstractMap
2、HashMap 允许将 null 作为 key 或者 value 存储,而 Hashtable 不允许
3、HashMap 把 Hashtable 的 contains 方法去掉了,改成了 containsvalue 和containsKey 。因为contains方法容易让人引起误解。
4、最大的不同是, Hashtable 是线程安全的, HashMap 是非线程安全的。
public void testMap() {
Map<String, String> info = new HashMap<String, String>();
info.put("username", "Little");
info.put("password", "hello, world");
info.put("email", "[email protected]");
info.put("phone", "110");
info.put("nothing", "error");
info.put(null, "the key is null"); // key为null
info.put("the value is null", null); // value为null
display(info);
System.out.println("--- Remove 'error':"
+ info.remove("error") + " ---");
display(info);
System.out.println("--- Remove 'nothing':'"
+ info.remove("nothing") + "' ---");
display(info);
System.out.println("--- Replace 'password':'"
+ info.put("password", "new, world") + "' ---");
display(info);
}
public void display(Map map) {
if (map == null) {
System.out.println("[null]");
return;
}
Set keys = map.keySet();
for (Object key : keys) {
System.out.println("<" + key + " = " + map.get(key) + ">");
}
System.out.println("Size: " + map.size());
}
我们可以尝试用 Hashtable 来实现这段代码,但是,当存入 null 键或者 null 值时(即代码中带注释的两行),都会抛出 NullPointerException ,因为 Hashtable 不允许存放 null 键或 null 值。
到现在,我们已经学习了三个 JDK 中哈希表的实现: HashSet、HashMap 和 Hashtable 。实际上, HashSet 的底层就是用 HashMap 来做的。这可以和我们写的 MyStack 比较来理解,MyStack 内部是使用 ArrayList 来存数数据,操作也是“委托”给 ArrayList 来做的。 HashSet 也是这个原理,只是 HashSet “委托”给 HashMap 来做。Set的另外一个实现类 TreeSet 也使用了这种方式,它底层使用 TreeMap 来做的。这种方式体现了面向对象的封装性。