线程安全性

HashMap:线程不安全
HashTable:线程安全,操作的方法都加了synchronized关键字

继承的父类

HashMap:AbstractMap
HashTable:Dictionary

允许null值

HashMap:最多只允许一条记录的key为null,允许多条记录的value为null
HashTable:key和value都不允许为null,否则会产生NullPointerException

哈希桶数组table的容量

HashMap: 默认16,初始化指定为大于指定值最接近的2次幂,始终为2^n,扩容后是2 oldCapacity
HashTable: 默认11,初始化指定多少初始就是多少,扩容后是2
oldCapacity + 1

注意:在HashMap中,哈希桶数组table的长度length大小必须为2的n次方(一定是合数),这是一种非常规的设计,常规的设计是把桶的大小设计为素数。相对来说素数导致冲突的概率要小于合数,具体证明可以参考这篇文章,Hashtable初始化桶大小为11,就是桶大小设计为素数的应用(Hashtable扩容后不能保证还是素数)。HashMap采用这种非常规设计,主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。

哈希桶初table始化的时机

HashMap:在第一次put时进行初始化
HashTable:调用构造函数时进行初始化

哈希桶初table可允许的最大容量

HashMap:2^30
HashTable:Integer.MAX_VALUE - 8 即 2^31 - 9

计算hash值的算法

HashMap:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
HashTable:key.hashCode()
注意:当key为null时,HashTable使用key.hashCode()会产生NullPointerException,
这就是HashTable key不能为null的原因。

根据Hash值计算索引位置的算法

HashMap:hash & (tab.length - 1)
HashTable:(hash & 0x7FFFFFFF) % tab.length
注意:0x7FFFFFFF表示成二进制是01111111 11111111 11111111 11111111,
hash & 0x7FFFFFFF 的目的是去除首位的符号位,保证hash值是正数。

新put的节点产生hash冲突的处理

HashMap:链表法,尾插法,链表长度大于8且size > 64会转为红黑树,长度小于6会退化成链表
HashTable:链表法,头插法

达到扩容阈值之后执行扩容的时机

HashMap:在add新节点之后进行扩容
HashTable:在add新节点之前进行扩容

扩容后容量大小

HashMap:扩容后容量是2 oldCapacity
HashTable:扩容后容量是2
oldCapacity + 1