今天看代码,想到去年发生的HashMap发生的CPU使用率100%的事件,转载下当时看的三个比较不错的博客(很是推荐)html
参考:http://coolshell.cn/articles/9606.htmljava
http://github.thinkingbar.com/hashmap-analysis/git
http://developer.51cto.com/art/201102/246431.htm程序员
人物:github
王小胖:性别:男。程序员,工做经验1 year。爱好:吃肉、电玩、马小花。特技:吃肉不用考虑胃的容量。算法
马小花:性别:女。学生,工做经验0 year。爱好:蛋糕、臭美、王小胖。特技:可以降服王小胖……shell
/**2011年2月,电影《将爱情进行到底》火得不得了。周末,小胖也陪着小花去看这部电影。放映中,小花被影片中的靖哥哥和杜拉拉感动的一沓糊涂,而小胖则内心暗自后悔没有买一袋大爆米花来打发这无聊的时间。影片结束,小花已是鼻涕一把泪一把,小胖也只有装模做样地抽动了几下鼻子,一心只想着一下子是吃麦当劳仍是必胜客。*/数组
回到家中,小胖和小花各自玩着电脑。多线程
小花:胖子,你知道Hashtable和HashMap的区别吗?并发
小胖:略知。
小花:……装什么!!给我讲讲!!!
小胖:好的……
第一个区别就先来讲说继承关系吧。
若是你在baidu里google一下(技术类文章的搜索仍是推荐google),会发现网上的大体说法与“因为Java发展的历史缘由。Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现。”相同。这种说法没有错,可是胖子以为不够准确,特别是对于咱们这种大众菜鸟来讲,若是不去深究的话,可能就会形成一些理解上的差别。简单的认为Hashtable没有继承Map接口。胖子以前就犯过这样的错误(胖子认可本身笨,是真笨……)。
小花:那你怎么知道它们两个各自的继承关系呢?胖子。
咱们能够参考一下最新的JDK1.6的源码,看看这两个类的定义:
Java代码
能够看到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值。
Java代码
在咱们使用上面的方法时,如参数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()方法来判断了。(详见源码剖析)
Java代码
结果:
Java代码
HashMap对于null值key的处理网上有说“null 用new Object()来代替,其Entry.hashCode=0,并且在取出的时候还会还回null的。”胖子我在读取源码的过程当中看到了null值的hash值确实是0 (内部实现的数组中的index也是),可是能力有限没有看到转为new Object()的过程。
小花: 原来hashMap的containsKey还有这么个陷阱,之后肥婆要当心了。
第四个不一样就是它们两个Hash值的获取方式了。
仍是经过源代码源代码,Hashtable是直接使用key对象的hash值。
Java代码
而HashMap则是利用key对象的hash值从新计算一个新的hash值。
Java代码
小花:胖子,都用了hash算法,你给我讲讲Hash算法吧。
小胖:嗯……之后的,今天我比较忙(实际上是不会)。
小花:你是否是不会啊?嘿嘿(坏笑)。
小胖:什么不会……谈下一话题……
第五个不一样就是Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。
HashMap中内部数组的初始容量是16, 加载因子为0.75,并且数组容量增容后也要是2指数次幂:
Java代码
HashTable中的内部数组的初始容量是11,加载因子也是0.75数组的增容方式为(oldCapacity * 2 + 1):
Java代码
第六个不一样咱们从它们两个遍历方式的内部实现上来讲。
Hashtable HashMap都使用了 Iterator。而因为历史缘由,Hashtable还使用了Enumeration的方式 。
小花:Iterator和Enumeration的区别是什么啊?给我讲讲。
小胖:我不是说我没有时间嘛,下回的。
小花:我都记下来,免得你给我混过去。(拿起笔开始记帐中)
小胖:……(紧张)
第七个不一样时它们的拷贝构造函数的不一样。
依然是经过查看源码,能够发现它们两个对于拷贝函数初始容量的不一样值。
HashMap的实现是:
Java代码
而Hashtable的实现是:
Java代码
小胖:今天讲的已经不少了。我有点饿了,肥婆。
小花:看你今天的表现这么好。走,带你去吃烤肉去。
小胖:哈哈,肥婆万岁。