Hashtable和HashMap引发的血案(一)

2014-11-24 00:14:14 · 作者: · 浏览: 0

FROM:王胖子的黑板报

人物:

王小胖:性别:男。程序员,工作经验1 year。爱好:吃肉、电玩、马小花。特技:吃肉不用考虑胃的容量。

马小花:性别:女。学生,工作经验0 year。爱好:蛋糕、臭美、王小胖。特技:能够降服王小胖……

/**2011年2月,电影《将爱情进行到底》火得不得了。周末,小胖也陪着小花去看这部电影。放映中,小花被影片中的靖哥哥和杜拉拉感动的一沓糊涂,而小胖则心里暗自后悔没有买一袋大爆米花来打发这无聊的时间。影片结束,小花已经是鼻涕一把泪一把,小胖也只有装模作样地抽动了几下鼻子,一心只想着一会儿是吃麦当劳还是必胜客。*/

回到家中,小胖和小花各自玩着电脑。

小花:胖子,你知道Hashtable和HashMap的区别吗?

小胖:略知。

小花:……装什么!!给我讲讲!!!

小胖:好的……

第一个区别就先来说说继承关系吧。

如果你在baidu里google一下(技术类文章的搜索还是推荐google),会发现网上的大致说法与“由于Java发展的历史原因。Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。”相同。这种说法没有错,但是胖子觉得不够准确,特别是对于我们这种大众菜鸟来说,如果不去深究的话,可能就会造成一些理解上的差异。简单的认为Hashtable没有继承Map接口。胖子之前就犯过这样的错误(胖子承认自己笨,是真笨……) 。

小花:那你怎么知道它们两个各自的继承关系呢?胖子。

我们可以参考一下最新的JDK1.6的源码,看看这两个类的定义:


public class Hashtable
extends Dictionary
implements Map, Cloneable, java.io.Serializable {…}
public class HashMap
extends AbstractMap
implements Map, Cloneable, Serializable {…}


可以看到hashtable也是继承了Map接口。它们的不同是Hashtable(since JDK1.0)就继承了Dictionary这个抽象类,而HashMap(since JDK1.2)继承的则是AbstractMap这个抽象类。因为在Hashtable中看到继承Map后所实现的方法是JDK1.2版本时加上去的,所以胖子猜想可能是在JDK 1.2开发时Sun工程师出于统一的考虑使得Hashtable也继承了Map接口。

小花:哦,原来JDK源码还能看出来这个。

小胖:……后面还能看出更多东西的。

小花:好期待啊。


第二个区别我们从同步和并发性上来说说它们两个的不同。


可以通过这两个类得源码来分析,Hashtable中的主要方法都做了同步处理,而HashMap则没有。可以说Hashtable在默认情况支持同步,而HashMap在默认情况下是不支持的。我们在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。对HashMap的同步处理可以使用Collections类提供的synchronizedMap静态方法;或者直接使用JDK5.0之后提供的java.util.concurrent包里的ConcurrentHashMap类。

小胖:synchronizedMap静态方法和ConcurrentHashMap类我会以后再给你详细讲一下的。肥婆。

小花:你保证啊。钥匙忘了你知道后果的。

小胖:好的……


第三个区别就是它们对于null值的处理方式了。


我们依然能够从源代码中得知,Hashtable中,key和value都不允许出现null值。


public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
//…
}

在我们使用上面的方法时,如参数value为null,可以从代码中直接看出程序会抛出NullPointerException;而在key为null时,则会在“int hash = key.hashCode();“这段计算Hash值的过程中抛出NullPointerException。而在在HashMap中,允许null作为key存在,并且和其他key的特性一样,这样的null值key只能有一个;另外HashMap允许多个value为null。这样大家就要注意了, HashMap中就不能用get(key)方法来判断HashMap中是否存在某个key,因为value为null和不存在该key的Entry都会返回null值,而应该用containsKey()方法来判断了。


import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class TestCase {
public static void main(String[] args) {
Map hashMap = new HashMap();
hashMap.put(0, null);
hashMap.put(1, "one");
hashMap.put(2, "two");
hashMap.put(null, "null");
for(Entry e : hashMap.entrySet()) {
System.out.println("Key: " + e.getKey() + " -- Value: " + e.getValue());
}
System.out.println(hashMap.get(0));
System.out.println(hashMap.get(4));
System.out.println("Contains key 0 :" + hashMap.containsKey(0));
System.out.println("Contains key 4 :" + hashMap.containsKey(4));
System.out.println("Contains value null :" + hashMap.containsValue(null));
}
}

结果:


Key: null -- Value: null
Key: 0 -- Value: null
Key: 1 -- Value: one
Key: 2 -- Value: two
null
null
Contains key 0 :true
Contains key 4 :false
Contains value null :true

HashMap对于null值key的处理网上有说“null 用new Object()来代替,其Entry.hashCode=0,而且在取出的时候还会还回null的。”胖子我在读取源码的过程中看到了null值的hash值确实