# HashTable
HashMap和HashTable是两种不同的哈希表数据结构,它们在多个方面有所不同:
**数据结构:**
HashMap和HashTable都使用哈希表来存储键值对。在数据结构上是基本相同的,都创建了一个继承自Map.Entry的私有的内部类Entry,每一个Entry对象表示存储在哈希表中的一个键值对。
Entry对象唯一表示一个键值对,有四个属性:
-K key 键对象
-V value 值对象
-int hash 键对象的hash值
-Entry entry 指向链表中下一个Entry对象,可为null,表示当前Entry对象在链表尾部
**线程安全性**
HashTable是线程安全的,这意味着所有方法都是同步的,因此在多线程环境下使用HashTable时不需要额外的同步措施,但这也降低了性能;HashMap不是线程安全的,因此在多线程环境下使用它时必须手动同步,或者使用Collections.synchronizedMap()方法来获得线程安全的实现。
**Null值**
HashTable不允许键或值为null,而HashMap允许键和值为null。
**继承和实现**
都是Map接口的实现
HashMap继承自AbstractMap类,实现了Map接口;HashTable继承自Dictionary类,实现了Map接口。
**默认容量和扩容策略**
HashTable的初始容量为11,填充因子为0.75,扩容时容量翻倍加1;HashMap的初始容量默认为16,填充因子为0.75,扩容时容量翻倍。
**计算hash的方法**
HashTable直接使用键的hashCode对table数组的长度进行取模计算hash;HashMap使用键的hashCode进行二次hash后对table数组长度取模。
**底层实现**
两者底层实现都是数组+链表结构。
**性能**
由于HashTable是线程安全的,所以在多线程环境下性能较低;HashMap在单线程环境下性能较好,但在多线程环境下需要通过额外的同步措施或使用ConcurrentHashMap来提高性能。
**方法**
HashMap去掉了HashTable的contains方法,改为提供containsValue和containsKey方法,因为contains方法容易让人误解。
总结来说,HashMap的非线程安全和允许null值方面提供了更好的灵活性,而HashTable提供了线程安全和更强的类型安全保证,但牺牲了一定的性能和灵活性。
# HashSet
HashSet 底层是HashMap,HashMap底层是(数组+链表+红黑树)
添加一个元素时,先得到hash值,会转成 -> 索引值
找到存储数据表table,看这个索引位置是否已经存放了元素
如果没有存放,则直接添加
如果存放了,调用 equals() 比较,如果相同,就放弃添加,如果不相同,则添加到最后
在java8中,如果一条 链表 的元素个数 大于 TREEIFY_THRESHOLD(默认是8)(链表准备添加第九个的时候) ,并且 table 的大小 >= MIN_TREEIFY_CAPACITY(默认是64),就会进行树化(红黑树)
扩容和哈希表一样
负载因子0.75
当前数组长度 > 容量 * 0.75时,就会触发扩容