现在HashTable在开发中很少使用。如果你要保证线程安全,推荐使用ConcurrentHashMap
1.线程安全
两者最主要的区别在于Hashtable所有方法都加上了synchronized,线程安全,而HashMap则非线程安全,但Hashtable性能差,非并发条件下不建议 使用Hashtable
2.值为null
HashMap允许key 和 value为null,以null作为key时,会存储在table数组的下标为0的位置上
Hashtable不允许key 和 value为null,会抛出空指针异常
3.初始容量不同
HashMap的初始容量为16
Hashtable初始容量为11
两者的负载因子默认都是0.75
4.扩容机制不同
HashMap/Hashtable元素个数 > 阈值(数组长度 * 负载因子)时扩容
HashMap扩容时是当前容量翻倍即:capacity * 2
Hashtable扩容时是容量翻倍+1即:capacity * 2 + 1。
5.计算hash 与 获取数组下标的算法不同
Hashtable调用key的hashcode获取哈希值,然后对table数组的长度直接进行取模获取数组下标
HashMap对key的hashcode进行了二次hash,以获得更好的散列值,通过与运算获取数组下标
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length-1);
6.底层数据结构不同
jdk1.7底层都是数组 + 链表
jdk1.8,HashMap加入了红黑树,而Hashtable 没有这样的机制。
7.父类不同
HashMap是继承自AbstractMap类
HashTable是继承自Dictionary(已被废弃)
不过它们都实现了同时实现了map、Cloneable(可克隆)、Serializable(可序列化)这三个接口。
8.部分API不同
Hashtable比HashMap多提供了elments() 和contains() 两个方法。(contains和containsValue的功能是相同的)
HashMap没有重写toString()方法,HashTable支持重写了toString()方法
9. 遍历方式不同
HashMap只支持Iterator遍历
HashTable支持Iterator和Enumeration两种方式遍历
10.迭代器不同
HashMap的迭代器(Iterator)是fail-fast迭代器,
Hashtable的enumerator迭代器不是fail-fast的。
所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出并发修改异常
ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出
ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。
而Hashtable 则不会。