1、推出时间:
HashMap JDK 1.2 之后推出的,而Hashtable是在 JDK 1.0 时推出的,现在Hashtable基本上已经被弃用了
2、扩容机制:
Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。创建时,如果给定了容量初始值,那么Hashtable会直接使用你给定的大小,而HashMap会将其扩充为2的幂次方大小。也就是说Hashtable会尽量使用素数、奇数。而HashMap则总是使用2的幂作为哈希表的大小。之所以会有这样的不同,是因为Hashtable和HashMap设计时的侧重点不同。Hashtable的侧重点是哈希的结果更加均匀,使得哈希冲突减少。当哈希表的大小为素数时,简单的取模哈希的结果会更加均匀。而HashMap则更加关注hash的计算效率问题。在取模计算时,如果模数是2的幂,那么我们可以直接使用位运算来得到结果,效率要大大高于做除法。
3、哈希值计算:
Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。
HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。
4、数据结构上:
HashMap在jdk1.8在原先的数组+链表的结构进行了优化,将实现结构变为数组+链表+红黑树,可以防止在一个哈希桶位置链表过长,影响性能,在一条链表节点元素大于8的时候,会将链表封装成红黑树。Hashtable继续使用数组+链表的方式实现。
5、线程安全与否:
多线程并发情况下,Hashtable是同步的,所以线程安全的,但是性能较低,HashMap是异步的,线程不安全,但是性能高。
6、对Null key 和Null value的支持不同
Hashtable既不支持Null key也不支持Null value,HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键,因为当get()方法返回null值时,可能是 HashMap中没有该键,也可能使该键所对应的值为null,所以应该用containsKey()方法来判断。