唉,面试的额时候,十次有八次都会问到Hashtable和HashMap有什么不同,那时候不知道啊,感觉能用会用,能实现就可以了啊,所以也没有考虑那么多。现在有时间,抽个空,查查资料,总结一下这两者的区别,以加强记忆,以防万一。
这两个类具体点说呢,有三个最主要的不同之处,首先,看一下类的定义:
public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable
public class Hashtable<K, V> extends Dictionary<K, V>
implements Map<K, V>, Cloneable, Serializable
从定义上可以看出,两者的父类不一样,Hashtable是继承自陈旧的Dictionary类,而HashMap是继承自AbstractMap。
其次就是,方法同步的问题,看源码得知,Hashtable的方法基本上都是同步的,而HashMap的方法并不是,也就是说,你可以不采取任何的措施而在多个线程中用一个Hashtable,但是你必须提供外同步才能用HashMap。要想创建一个线程安全的Map对象,可以用Collections类的synchronizedMap()方法实现来返回一个封装的对象。但是这样做也是有坏处的,当你不需要同步的时候,你不能切断HashMap中的同步,而且同步增加的处理费用消耗。
最后一点不同之处是,HashMap可以允许key与value值是空的,而Hashtable是不可以的。下面看源码:
HashMap的put方法:
@Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
// No entry for (non-null) key is present; create one
modCount++;
if (size++ > threshold) {
tab = doubleCapacity();
index = hash & (tab.length - 1);
}
addNewEntry(key, value, hash, index);
return null;
}
(1)上面说过,方法没有同步;(2)通过第2-3行得知,允许key值为null;(3)通过24行看出,并没有对value值做空判断,所以,value值可也为null
现在进到方法putValueForNullKey中看:
private V putValueForNullKey(V value) {
HashMapEntry<K, V> entry = entryForNullKey;
if (entry == null) {
addNewEntryForNullKey(value);
size++;
modCount++;
return null;
} else {
preModify(entry);
V oldValue = entry.value;
entry.value = value;
return oldValue;
}
}
很明显,一个私有的方法,先判断entry是不为null,即以前是否已经添加过一个key值为null的数据了,没有则新new一个,有则替换旧的value值为新的value。
下面看一下Hashtable的put方法:
public synchronized V put(K key, V value) {
if (key == null) {
throw new NullPointerException("key == null");
} else if (value == null) {
throw new NullPointerException("value == null");
}
int hash = Collections.secondaryHash(key);
HashtableEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
HashtableEntry<K, V> first = tab[index];
for (HashtableEntry<K, V> e = first; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
// No entry for key is present; create one
modCount++;
if (size++ > threshold) {
rehash(); // Does nothing!!
tab = doubleCapacity();
index = hash & (tab.length - 1);
first = tab[index];
}
tab[index] = new HashtableEntry<K, V>(key, value, hash, first);
return null;
}
(1)方法是同步的;(2)通过2—6行看出,都是对key以及value值做了非空判断,如若是null,抛空指针异常总结:HashMap是Hashtable轻量级的实现,但是是非线程安全的。两者都实现了Map接口。
HashMap允许null作为一个key或者value,而Hashtable是不允许的。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自 己为它的方法实现同步,而HashMap 就必须为之提供外同步(Collections.synchronizedMap)。
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。