类继承体系上的区别

HashMap和Hashtable都实现了Map,Cloneable,Serializable接口。但两者不同的是HashMap继承的是AbstractMap而Hashtable继承的是Dictionary。Dictionary已经被弃用。Hashtble仅仅比HashMap多两个公开的方法,分别是:elements(来自已弃用的Dictionary)和contains。而contains和HashMap的containsValue类似。

1
2
3
4
5
6
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable

public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable

对NULL key和NULL Vulue的支持

在HashMap中是支持null键和null值的。但是在Hashtable中是不支持null值的。否则会抛出NullPointerException异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}

addEntry(hash, key, value, index);
return null;
}

实现细节上的差别

HashMap中默认容量是16,默认的负载因子是0.75,每次扩容扩容为原来的两倍.而Hashtable中默认的容量是11,默认的负载因子为0.75,每次扩容扩容为原来的2n+1倍。Hashtable尽量使用素数、奇数来作为容量,而HashMap总是使用2的幂作为哈希表的大小。当哈希表的大小为素数时,简单的取模运算会使结果更加均匀。但是在取模运算的时候,如果模数是2的倍数的话,可以使用位运算来得到结果,效率要大大高于除法。所以从哈希计算的效率上来讲,HashMap更胜一筹。

线程安全

Hashtable是线程安全的,而HashMap不是。在多线程的环境下,Hashtable不需要额外的同步,而HashMap则不行。在Hashtable中所有的公开方法都是用了synchronized关键字。