HashMap和HashTable有什么差异?在口试和被口试的进程中,我问过也被问过这个问题,也见过了不少答复,本日抉择写一写本身心目中的抱负谜底。
代码版本
JDK每一版本都在改造。本文接头的HashMap和HashTable基于JDK 1.7.0_67。源码见这里
1. 时间
HashTable发生于JDK 1.1,而HashMap发生于JDK 1.2。从时间的维度上来看,HashMap要比HashTable呈现得晚一些。
2. 作者
以下是HashTable的作者:
以下代码及注释来自java.util.HashTable * @author Arthur van Hoff * @author Josh Bloch * @author Neal Gafter
以下是HashMap的作者:
以下代码及注释来自java.util.HashMap * @author Doug Lea * @author Josh Bloch * @author Arthur van Hoff * @author Neal Gafter
可以看到HashMap的作者多了大神Doug Lea。不相识Doug Lea的,可以看这里。
3. 对外的接口(API)
HashMap和HashTable都是基于哈希表来实现键值映射的东西类。接头他们的差异,我们首先来看一下他们袒露在外的API有什么差异。
3.1 Public Method
下面两张图,我画出了HashMap和HashTable的类担任体系,并列出了这两个类的可供外部挪用的果真要领。
从图中可以看出,两个类的担任体系有些差异。固然都实现了Map、Cloneable、Serializable三个接口。可是HashMap担任自抽象类AbstractMap,而HashTable担任自抽象类Dictionary。个中Dictionary类是一个已经被废弃的类,这一点我们可以从它代码的注释中看到:
以下代码及注释来自java.util.Dictionary * <strong>NOTE: This class is obsolete. New implementations should * implement the Map interface, rather than extending this class.</strong>
同时我们看到HashTable比HashMap多了两个果真要领。一个是elements,这来自于抽象类Dictionary,鉴于该类已经废弃,所以这个要领也就没什么用处了。另一个多出来的要领是contains,这个多出来的要领也没什么用,因为它跟containsValue要领成果是一样的。代码为证:
以下代码及注释来自java.util.HashTable public synchronized boolean contains(Object value) { if (value == null) { throw new NullPointerException(); } Entry tab[] = table; for (int i = tab.length ; i-- > 0 ;) { for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) { if (e.value.equals(value)) { return true; } } } return false; } public boolean containsValue(Object value) { return contains(value); }
所以从果真的要领上来看,这两个类提供的,是一样的成果。都提供键值映射的处事,可以增、删、查、改键值对,可以对建、值、键值对提供遍历视图。支持浅拷贝,支持序列化。
3.2 Null Key & Null Value
HashMap是支持null键和null值的,而HashTable在碰着null时,会抛出NullPointerException异常。这并不是因为HashTable有什么非凡的实现层面的原因导致不能支持null键和null值,这仅仅是因为HashMap在实现时对null做了非凡处理惩罚,将null的hashCode值定为了0,从而将其存放在哈希表的第0个bucket中。我们一put要领为例,看一看代码的细节:
以下代码及注释来自java.util.HashTable public synchronized V put(K key, V value) { // 假如value为null,抛出NullPointerException if (value == null) { throw new NullPointerException(); } // 假如key为null,在挪用key.hashCode()时抛出NullPointerException // ... } 以下代码及注释来自java.util.HasMap public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } // 当key为null时,挪用putForNullKey非凡处理惩罚 if (key == null) return putForNullKey(value); // ... } private V putForNullKey(V value) { // key为null时,放到table[0]也就是第0个bucket中 for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(0, null, value, 0); return null; }
4. 实现道理
本节接头HashMap和HashTable在数据布局和算法层面,有什么差异。
4.1 数据布局
HashMap和HashTable都利用哈希表来存储键值对。在数据布局上是基内情同的,都建设了一个担任自Map.Entry的私有的内部类Entry,每一个Entry工具暗示存储在哈希表中的一个键值对。
Entry工具独一暗示一个键值对,有四个属性:
-K key 键工具
-V value 值工具
-int hash 键工具的hash值
-Entry entry 指向链表中下一个Entry工具,可为null,暗示当前Entry工具在链表尾部