断断续续写了半个月,今天终于把TreeMap
容器中的红黑树
搞定了,现在来水一篇又快又短
的Java Map容器
总结博客 😂😂。
注明:本篇博客不会涉及容器的源码什么的,主要是总结各个map
容器的底层实现特点、主要运用场景。如果你需要详细了解更多关于Java
中的map
容器实现的细节,文末会提供我前面写的源码分析的博客链接,欢迎阅读。
Java中的常见五种map容器源码分析总结目录
一、Java
中的Map
容器概述
Map
是一种存储key-value
(键值对
)的容器,在Java中,常见的Map
接口的实现类有五种,分别是HashMap
、Hashtable
、ConcurrentHashMap
、LinkedHashMap
、TreeMap
。五种容器的关系如下图:
顺带一提,貌似有不少人觉得map
就是hashmap
、hashmap
就是map
,把hash
与map
两个概念混为一谈。然而map
是用于存储key-value
的虚拟容器,按照key的hash值将节点散列到一个table数组
(也称hash表
)的table[i]
(也称hash桶
)中。等你看完TreeMap
的底层数据结构就会发现,不通过key.hash值
,也可以实现map容器
。
二、HashMap
容器
1、HashMap
概述
Java中的HashMap
底层使用一个table数组
存放节点,使用链表(JDK 1.8
新增红黑树
)解决hash冲突
(多个元素的hash值
散列到同一个table[i]
中)的问题。
2、HashMap
数据结构示意图
3、HashMap
特点
- ①、存取高效,不支持并发读写操作(没有引入锁任何机制)
- ②、table数组的长默认是16,并且每次扩容为原来的2倍(长度总是保持为2的次幂,方便hash值求余)
- ③、支持key、value为null的键值对插入
4、HashMap
源码分析链接
Java容器之HashMap源码分析(妈妈再也不用担心我不懂HashMap了)
三、Hashtable
容器
1、Hashtable
概述
Java中的Hashtable
底层同样是使用一个table数组
存放节点,使用链表解决hash冲突
(多个元素的hash值
散列到同一个table[i]
中)的问题。不过引入了锁机制
(通过synchronized关键字,锁为this,每次锁住整个容器),支持并发操作。
2、Hashtable
数据结构示意图
3、Hashtable
特点
- ①、写入、删除效率相对较低。引入锁机制,通过synchronized关键字修饰方法(同步方法),锁对象为this,每次锁住整个容器,锁的粒度太大。
- ②、table数组的长默认是11,并且每次扩容为原来的2倍 + 1
- ③、不支持key、value为null的键值对插入
4、Hashtable
源码分析链接
Java容器之Hashtable源码分析(关于Hashtable的这些细节你可能还不知道)
四、ConcurrentHashMap
容器
1、ConcurrentHashMap
概述
Java中的ConcurrentHashMap
底层同样是使用一个table数组
存放节点,使用链表解决hash冲突
(多个元素的hash值
散列到同一个table[i]
中)的问题。在JDK 1.8前的版本中引入段的概念,使用RententLock
锁,并且分段锁(对每个段分别设置一个锁),相比于Hashtable锁整个容器,并发操作时,效率提高了不少。
在JDK 1.8
的时候,又取消了段的概念,重新使用synchronized
关键字(同步代码块)。不过每次锁住的对象的是需要修改的table[i]
(hash桶
),并且在各大方法中尽量减少了同步代码块中的代码量,从而减少了锁的粒度,并发操作时,效率提高了不少。在扩容时,支持多个线程同时进行扩容(并发扩容)。
2、ConcurrentHashMap
数据结构示意图
3、ConcurrentHashMap
特点
- ①、写入、删除效率相比与Hashtable容器较高。引入锁机制,通过synchronized关键字(同步代码块),锁对象为即将修改的table[i](hash桶),锁的粒度小。
- ②、table数组的长默认是16,并且每次扩容为原来的2倍(长度总是保持为2的次幂,方便hash值求余)
- ③、不支持key、value为null的键值对插入
4、ConcurrentHashMap
源码分析链接
Java容器之ConcurrentHashMap源码分析(JDK 1.7与JDK 1.8对比)
五、LinkedHashMap
容器
1、LinkedHashMap
概述
Java中的LinkedHashMap
是HashMap
的子类,也可以说是对HashMap
的封装。对外展示的是一个双向链表
,链表中的元素顺序,就是插入节点的顺序。
2、LinkedHashMap
数据结构示意图
3、LinkedHashMap
特点
- ①、LinkedHashMap是对HashMap的进一步封装,所以实现细节基本一致
- ②、对外展示为双向链表,链表节点中的顺序为插入时的顺序(其实也可以修改为访问顺序)
4、LinkedHashMap
源码分析链接
Java容器之LinkedHashMap源码分析(看看确定不点进来?进来真不点?)
六、TreeMap
容器
1、TreeMap
概述
Java中的TreeMap
容器底层是通过维护一棵红黑树来存储key-value
节点,与hash没有任何关系。树中的节点按照key
的大小排序,可以手动指定key的比较器comparator
。
2、TreeMap
数据结构示意图
3、TreeMap
特点
- ①、读写高效,查找的复杂度在O(log2n)级别。(不支持并发读写,为引入锁)
- ②、节点按照key升序排列,可指定key的比较器comparator
- ③、不支持key为null的key-value插入
4、TreeMap
源码分析链接
七、总结
HashMap
、LinkedHashMap
、Hashtable
、ConcurrentHashMap
这四个都是通过table数组,并结合hash散列存放节点,前两者不支持并发读写,效率较高,后两者支持并发,并且ConcurrentHashMap
的效率更高些。TreeMap
容器通过红黑树存储key-value
节点,节点按照key的大小排序,查找、插入比较高效,时间复杂度在O(log2n)级别。