相同点
都是Map接口的子类,以键值对的形式存储数据,底层都是数组+链表的形式实现的,在JAVA8 之后,hashmap的链表长度超过8后会转化成红黑树,提高查找效率。
继承关系
HashMap继承了abstractMap实现了Map接口
Hashtable继承了Dictionary实现了Map接口
初始大小和扩容方式
HashMap数组初始大小为16,增加方式为2的指数幂
HashTable中数组默认大小为11,扩容方式为原数组大小*2+1
计算hash值
Hashtable计算hash是直接使用key的hashcode对table数组的长度直接进行取模
数组下标,直接用key的hashcode和0x7FFFFFFF做位与运算,在对数组长度进行取模
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
HashMap计算hash对key的hashcode进行了二次hash,以获得更好的散列值,然后对table数组长度减一进行位与运算
第一次hash:key的hashcode与key的hashcode无符号右移16位进行异或运算得到一个hash值
第二次hash:用第一次的得到的hash值和Entry数组的长度减一做位与运算。得出数组下标
当key为null时key的hash值为0。
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length-1);
}
存放null值
Hashmap允许有一个key为null和多个value为null,当key为null时hash算法会直接返回0
Hashtable不允许key和value为null,当key或value为null时,会抛出空指针异常
线程安全
HashMap是线程不安全的
HashTable是线程安全的,方法被synchronized修饰