简单总结 HashMap、Hashtable、ConcurrentHashMap 之间的区别,基于 JDK 1.8.0_191
先说结论,暂时有以下几个需要注意的不同点:
- 继承、实现接口不同
- 初始大小、扩容倍数不同
- 线程安全
- NULL KEY,NULL VALUE 支持不同
- 计算 Hash 值的方式不同
1. 继承、实现接口不同
1 | public class HashMap<K,V> extends AbstractMap<K,V> |
- HashMap、ConcurrentHashMap 都继承于 AbstractMap 抽象类,但 Hashtable 继承于 Dictionary 抽象类。
- AbstractMap 实现了 Map 接口,而 Dictionary 没有。这使得 AbstractMap 具有更多的功能,而 Dictionary 逐渐被弃用。
2. 初始大小、扩容倍数不同
HashMap
1 | static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 |
Hashtable
1 | public Hashtable() { |
ConcurrentHashMap
1 | /** |
- 初始大小:HashMap、ConcurrentHashMap 都是 16,Hashtable 是 11
- 扩容倍数:HashMap、ConcurrentHashMap 2 倍、Hashtable (2n + 1) 倍。
3. 线程安全
1 | Hashtable: |
- Hashtable 添加元素方法加上了 synchronized 关键字,HashMap 没有,说明 HashMap 不适用于多线程环境。
- ConcurrentHashMap 添加元素时,只对需要变更的地方加锁。
4. NULL KEY,NULL VALUE 支持不同
通过观察它们的 put 方法,得到以下结论:
- Hashtable、ConcurrentHashMap 的 key、value 都不能为 null。
- HashMap value 可以为 null,而 key 为 null 时,该元素会放在 HashMap 第一位。
5. key 的索引计算方法不同
计算元素存放位置,会经过两步转化。Object -> int -> index,先将 key 使用 hash 方法转换为一个整数数字,然后对整型数字进行转化,得到这个对象在 map 中的索引。
Hashtable
1 | int hash = key.hashCode(); |
HashMap
1 | static final int hash(Object key) { |
- Hashtable 直接使用对象的 hashCode,然后再使用除留余数法来获得最终的位置。
- HashMap 在对象的 hashCode 之上,将 hashCode 的高16位和低16位进行异或,得到最终的位置。
总结
后面学习将对 HashMap,ConcurrentHashMap 源码进行分析总结。