- HashMap 和 HashTable 都是一个基于 hash 表实现的 K-V 结构的集合。
- HashTable 是 JDK1.0 引入的一个线程安全的集合类,因为所有数据访问的方法都加了一个 Synchronized 同步锁。
- Hashtable内部采用了数组+链表来实现。链表主要是用来解决hash表的一个hash冲突的问题。
- HashMap 是 JDK1.2 引入的一个线程不安全的集合类。HashMap 内部也使用了数组+链表来实现。但是在 JDK1.8 里面做了一些优化,引入了红黑树。当链表长度大于等于8,并且数组的长度大于64的时候,就会把链表转换为红黑树,提升数据查找了一个性能。
1、HashMap与HashTable区别:
可以把HashMap想象成一个无序的容器,而Hashtable则是一个有序的容器
- 线程是否安全:HashMap 是非线程安全的,HashTable 是线程安全的,因为 HashTable 内部的方法基本都经过synchronized修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap吧!);
- 对 Null key 和 Null value 的支持:HashMap可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个;HashTable 不允许有 null 键和 null 值,否则会抛出 NullPointerException。
- 初始容量大小和每次扩充容量大小的不同:
- 创建时如果不指定容量初始值,Hashtable默认的初始大小为 11,之后每次扩充,容量变为原来的
2n+1。HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的2倍。 - 创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为 2 的幂次方大小(HashMap 中的tableSizeFor()方法保证,下面给出了源代码)。也就是说 HashMap 总是使用 2 的幂作为哈希表的大小,后面会介绍到为什么是 2 的幂次方。
- 底层数据结构: JDK1.8 以后的 HashMap在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。(hashtable的底层:数组+链表)
- 效率: 因为线程安全的问题,HashMap 要比 HashTable效率高一点。另外, HashTable基本被淘汰,不要在代码中使用它(原因:①使用synchronized来保证线程安全,会锁住整个哈希表。在线程竞争激烈的情况下效率非常低下)
2、HashMap与TreeMap的区别
HashMap和TreeMap都是实现了Map接口的类,它们的主要区别有:
可以把HashMap想象成一个无序的容器,而TreeMap则是一个有序的容器
- HashMap是基于哈希表的,而TreeMap是基于红黑树的;
- HashMap的key可以是null,而TreeMap的key不能为null;
- HashMap的key-value对是无序的,而TreeMap的key-value对是有序的
- HashMap的查找速度更快,而TreeMap的查找速度更慢;(HashMap根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。TreeMap是基于红黑树的,它是按照键的排序进行存储的,默认是按照升序排序)
- HashMap的实现比TreeMap更简单,而TreeMap的实现比HashMap更复杂。
3、HashMap与HashSet的区别
HashMap和HashSet都是基于哈希表的,它们的主要区别有:
可以把HashMap想象成一个映射表,它存储的是键值对,而HashSet是一个集合,它存储的是单个的值
- 存储方式:HashMap是一个映射表,它存储的是键值对,而HashSet是一个集合,它存储的是单个的值。
- 元素的唯一性:HashMap中的key是唯一的,而value可以重复;而HashSet中的元素是唯一的,不能重复。
- 对null的支持:HashMap可以存储一个null键和多个null值,而HashSet最多存储一个null值。
- 底层数据结构:HashMap是基于哈希表实现的,而HashSet是基于HashMap实现的,底层也是使用哈希表。
- 使用场景:HashMap适用于需要通过键值对来查找元素的场景,而HashSet适用于需要存储唯一元素的场景。