1.父类和实现接口不同
HashMap:父类AbstractMap,实现接口Cloneable,Serializable,map
HashTable:父类Dictionary, 实现接口Cloneable,Serializable,map
2.相关方法
HashTable比HashMap多了两个方法,elments(),contain()
- elments() 方法继承自Hashtable的父类Dictionnary。elements() 方法用于返回此Hashtable中的value的枚举。
- contains()方法判断该Hashtable是否包含传入的value。它的作用与containsValue()一致。事实上,contansValue() 就只是调用了一下contains() 方法。
3.对Null key 和Null value的支持不同
- HashTable不支持nullKey和nullvalue,
当null key时,调用put方法,运行到一步就会出现空指针异常。
当null value时,hashtable也做了限制,报空指针异常。
If(value==null) {
Throw new NullpointerException();
}
2.HashMapkey为null的键只有一个,而value为null的键可以有多个。
当get()方法返回null值时,可能时HashMap中没有该键,也可能时改键值为null。
因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,而应该用containsKey()方法来判断。
4.线程安全方面
- Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。在多线程并发的环境下,可以直接使用Hashtable,不需要自己为它的方法实现同步。
- HashMap不是线程安全的,在多线程并发的环境下,可能会产生死锁等问题。
5.效率
- HashMap不是线程安全的,但是它的效率要比HashTable好很多。HashMap大多用于单线程操作。
- 当需要多线程操作时,可以使用线程安全的ConcurrentHashMap.ConcurrentHashMap是线程安全的,它的效率比HashTable要快好几倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行*。
6.遍历方式的内部实现上不同
- Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式
- HashMap的Iterator是fail-fast迭代器。
- JDK8之前的版本中,Hashtable是没有fast-fail机制的。在JDK8及以后的版本中 ,HashTable也是使用fast-fail的
7.初始容量大小和每次扩充容量大小的不同
- HashTable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。
- HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。
8.计算hash值的方法不同
Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。
- HashTable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。
- HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算。
为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。