HashMap和HashTable都实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆,实现Map接口。
HashMap的父类AbstractMap类。
Hashtable的父类Dictionary。
Hashtable既不支持Null key也不支持Null value。都会抛空指针。
HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。
Hashtable是线程安全的,它的每个方法中都加入了Synchronize方法。
HashMap不是线程安全的。
Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。
HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。
计算hash值的方法不同,Hashtable直接使用对象的hashCode。
计算hash值的方法不同,HashMap使用 扰动函数。先获取对象的hashCode,然后在将hashCode右移16位(高位到低位),然后将2次的值异或求值得出一个新的hash值(h = key.hashCode()) ^ (h >>> 16)
HashMap 与 concurrentHashMap
hashMap线程不安全,concurrentHashMap线程是安全的,hashTable线程安全的
HashMap的线程不安全主要体现在下面两个方面:
1.在JDK1.7中 数组 + 链表,当并发执行扩容操作时会造成环形链和数据丢失的情况。
2.在JDK1.8中 数组 + 链表\红黑树,在并发执行put操作时会发生数据覆盖的情况。
1.8中当 链表长度>8 && table数组长度>=64 的时候会自动转换成红黑树
当插入数据时 table数组中某一个链表长度>8时 会执行 treeifybin的方法,方法中会先判断整个数组长度如果长度<64 就只执行扩容数据迁移的工作。 当数组长度>=64 执行转换红黑树的操作。
为什么HashMap的长度是2的n次幂
这样(数组长度-1)正好相当于一个“低位掩码”。“与”操作的结果就是散列值的高位全部归零,只保留低位值,用来做数组下标访问。 i = (n - 1) & hash
1.在JDK1.7中,当并发执行扩容操作时会造成环形链和数据丢失的情况。
2.在JDK1.8中,在并发执行put操作时会发生数据覆盖的情况。