1、两者父类不同
HashMap是继承自AbstractMap类,而Hashtable是继承自Dictionary类。
不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。
2、对外提供的接口不同
Hashtable比HashMap多提供了elments() 和contains() 两个方法。
elments() 方法继承自Hashtable的父类Dictionnary。
elements() 方法用于返回此Hashtable中的value的枚举。
contains()方法判断该Hashtable是否包含传入的value。
它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。
3、对null的支持不同
Hashtable:key和value都不能为null。
HashMap:
- key可以为null,但是这样的key只能有一个,因为必须保证key的唯一性;
- 可以有多个key值对应的value为null。
4、安全性不同
HashMap是线程不安全的
在多线程并发的环境下,可能会产生死锁等问题,因此需要开发人员自
己处理多线程的安全问题。
Hashtable是线程安全的
它的每个方法上都有synchronized 关键字,因此可直接用于多线程中。
虽然HashMap是线程不安全的,但是它的效率远远高于Hashtable,
这样设计是合理的,因为大部分的使用场景都是单线程。
当需要多线程操作的时候可以使用线程安全的ConcurrentHashMap。
ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。
因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
5、初始容量大小和每次扩充容量大小不同
map集合长度大于上一次扩容前长度1.75倍的时候再扩容。每次扩容都是原来的两倍。
例如:初始大小为 16 ,扩容因子 0.75 ,当容量为12的时候,比例已经是0.75 。
触发扩容,扩容后的大小为 32.
即当 元素个数 超过 容量长度的0.75倍时,进行扩容。
扩容增量:2*
原数组长度+1,如 HashTable的容量为11,一次扩容后是容量为23。
6、计算hash值的方法不同
HashMap中:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
HashMap 中的key值可以为null
key值的hash值的计算方法为:key的 hash 值高16位不变,低16位与高16位 异或 作为key最终的hash值。(h>>>16,表示无符号右移16位,高位补0)
Hashtable中
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;
}
Hashtable线程安全是因为添加了 synchronized 关键字,同时 Hashtable key值是不可以为空的。
其中 int index = (hash & 0x7FFFFFFF) % tab.length;
为了在hash为负值的情况下,去掉起符号位,所以和 0x7FFFFFFF
进行&
操作。
0x7FFFFFFF
二进制0111 1111 1111 1111 1111 1111 1111 1111
,负数与其进行&
操作将产生正整数。