1.容器整体结构:
HashMap的key和value都允许为null,HashMap遇到key为null的时候,调用putForNullKey方法进行处理,而对value没有处理。
Hashtable的key和value都不允许为 null。Hashtable遇到null,直接返回NullPointerException。
2.容量设定与扩容机制:
HashMap默认初始化容量为16,并且容器容量一定是 2的n次方,扩容时,是以原容量2倍的方式进行扩容。
Hashtable默认初始化容量为11,扩容时,是以原容量2倍再加1的方式进行扩容。
即int newCapacity = (oldCapacity << 1) + 1;。
3.散列分布方式(计算存储位置):
HashMap是先将key键的hashCode经过扰动函数扰动后得到hash值,然后再利用hash & (length - 1)的方式代替取模,得到元素的存储位置。
Hashtable则是除留余数法进行计算存储位置的(因为其默认容量也不是 2 的 n 次方。所以也无法用位运算替代模运算),int index = (hash & 0x7FFFFFFF) % tab.length;。
由于HashMap的容器容量一定是2的n次方,所以能使用hash & (length - 1)的方式代替取模的方式计算元素的位置提高运算效率,但Hashtable的容器容量不一定是2的n次方,所以不能使用此运算方式代替。
4.线程安全(最重要):
HashMap不是线程安全,如果想线程安全,可以通过调用synchronizedMap(Map<K,V> m)使其线程安全。但是使用时的运行效率会下降,所以建议使用ConcurrentHashMap容器以此达到线程安全。
Hashtable则是线程安全的,每个操作方法前都有synchronized修饰使其同步,但运行效率也不高,所以还是建议使用ConcurrentHashMap容器以此达到线程安全。
因此,Hashtable是一个遗留容器,如果我们不需要线程同步,则建议使用HashMap,如果需要线程同步,则建议使用 ConcurrentHashMap。