Java集合系列(一):List、Map、Set的基本实现原理总结
目录
一、主要内容
1.List
ArrayList
LinkedList
Vector
Vector与ArrayList的区别
Collections.SynchronizedList和Vector的区别
同步代码块和同步方法的区别
2.Map
HashMap
LinkedHashMap
HashTable
ConcurrentHashMap
3.Set
HashSet
LinkedHashSet
二、参考文献
一、主要内容
1.List
ArrayList
1)ArrayList是List接口的可变数组非同步实现,并允许包括null在内的所有元素。
2)底层使用数组实现
3)该集合是可变长度数组,数组扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量增长大约是其容量的1.5倍,这种操作的代价很高。
4)采用了Fail-Fast机制(通过记录modCount参数来标识多个线程操作),面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险
5)remove方法会让下标到数组末尾的元素向前移动一个单位,并把最后一位的值置空,方便GC
LinkedList
1)LinkedList是List接口的双向链表非同步实现,并允许包括null在内的所有元素。
2)底层的数据结构是基于双向链表的,该数据结构我们称为节点
3)双向链表节点对应的类Node的实例,Node中包含成员变量:prev,next,item。其中,prev是该节点的上一个节点,next是该节点的下一个节点,item是该节点所包含的值。
4)(没找到对应方法,indexof方法实现是从头开始循环判断元素)它的查找是分两半查找,先判断index是在链表的哪一半,然后再去对应区域查找,这样最多只要遍历链表的一半节点即可找到
Vector
1)动态数组实现的List,跟ArrayList一样,其容量能自动增长
2)JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(在操作数据的方法声明时加synchronized关键字:同步方法,在内部的迭代器操作数据的方法内部的代码块加Vector的synchronized的同步对象锁:同步代码块)
3)适用于快速访问和修改,不适用随机插入和删除(底层实现是对象数组的原因)
4)初始容量大小为10,扩容由初始容量和capacityIncrement共同决定
5)元素允许为null
6)现在已经基本不再使用,如果不需要线程安全的实现,推荐使用ArrayList代替Vector
Vector与ArrayList的区别
最大的是Vector是线程安全的,而ArrayList不是线程安全的。
1)ArrayList不可以设置扩展的容量,默认1.5倍;Vector可以设置扩展的容量,如果没有设置,默认2倍
2)ArrayList的无参构造方法中初始容量为0(初次调用add()会更新为10);Vector的无参构造方法中初始容量为10
3)Vector线程安全,ArrayList线程不安全
原文:https://blog.csdn.net/lipinganq/article/details/78043065
Collections.SynchronizedList和Vector的区别
1) 如果使用add方法,那么他们的扩容机制不一样。
2) SynchronizedList可以指定锁定的对象。
(Collections.SynchronizedList只是使用同步代码块包裹了ArrayList的方法,而ArrayList和Vector中同名方法的方法体内容并无太大差异,所以在锁定范围和锁的作用域上两者并无却别。 在锁定的对象区别上,SynchronizedList的同步代码块锁定的是mutex对象,Vector锁定的是this对象。那么mutex对象是SynchronizedList在使用构造函数时可以传入一个Object,如果在调用的时候显示的传入一个对象,那么锁定的就是用户传入的对象。如果没有指定,那么锁定的也是this对象。)
同步代码块和同步方法的区别
1) 同步代码块在锁定的范围上可能比同步方法要小,一般来说锁的范围大小和性能是成反比的。
2) 同步块可以更加精确的控制锁的作用域(锁的作用域就是从锁被获取到其被释放的时间),同步方法的锁的作用域就是整个方法。
3) 静态代码块可以选择对哪个对象加锁,但是静态方法只能给this对象加锁。
静态变量与静态代码块加载时间:当类加载器将类加载到JVM中的时候就会创建静态变量,这跟对象是否创建无关。静态变量加载的时候就会分配内存空间。静态代码块的代码只会在类第一次初始化的时候执行一次。
2.Map
HashMap
1)HashMap是基于哈希表的Map接口的非同步实现,允许使用null值和null键,但不保证映射的顺序。
2)底层使用数组实现(Node<K,V>数组),数组中每一项是个单向链表,即数组和链表的结合体;
当链表长度大于一定阈值时,链表转换为红黑树,这样减少链表查询时间。
3)HashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Node对象。HashMap底层采用一个Node[]数组来保存所有的key-value对,
当需要存储一个Node对象时,会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;
当需要取出一个Node时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Node。
4)HashMap进行数组扩容需要重新计算扩容后每个元素在数组中的位置,很耗性能
5)采用了Fail-Fast机制,通过一个modCount值记录修改次数,对HashMap内容的修改都将增加这个值。迭代器初始化过程中会将这个值赋给迭代器的expectedModCount,在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map,马上抛出异常
HashMap结构:
相关参考:
Java中HashMap底层实现原理(JDK1.8)源码分析:
https://blog.csdn.net/tuke_tuke/article/details/51588156
LinkedHashMap
1)LinkedHashMap继承于HashMap,底层使用哈希表和双向链表来保存所有元素,并且它是非同步,允许使用null值和null键。
2)基本操作与父类HashMap相似,通过重写HashMap相关方法,重新定义了数组中保存的元素Entry,来实现自己的链接列表特性。
该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而构成了双向链接列表,用于记录前一个插入的元素和记录后一个插入的元素
相关参考:https://www.cnblogs.com/whgk/p/6169622.html
HashTable
1)Hashtable是基于哈希表的Map接口的同步实现,不允许使用null值和null键
2)底层使用数组实现,数组中每一项是个单链表,即数组和链表的结合体
3)Hashtable在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。Hashtable底层采用一个Entry[]数组来保存所有的key-value对,
当需要存储一个Entry对象时,会根据key的hash算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;
当需要取出一个Entry时,也会根据key的hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry。
4)synchronized是针对整张Hash表的,即每次锁住整张表让线程独占(使用同步方法)
ConcurrentHashMap
1)ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。
2)它使用了多个锁来控制对hash表的不同段进行的修改,每个段其实就是一个小的hashtable,它们有自己的锁。只要多个并发发生在不同的段上,它们就可以并发进行。
3)ConcurrentHashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。
4)与HashMap不同的是,ConcurrentHashMap使用多个子Hash表,也就是段(Segment),1.8中改用CAS+synchronized保证并发安全性,将存放数据的 HashEntry 改为 Node
5)ConcurrentHashMap完全允许多个读操作并发进行,读操作并不需要加锁。如果使用传统的技术,如HashMap中的实现,如果允许可以在hash链的中间添加或删除元素,读操作不加锁将得到不一致的数据。ConcurrentHashMap实现技术是保证HashEntry几乎是不可变的。
6)ConCurrentHashMap 在 jdk1.8 中主要做了两方面的改进。
(1) 取消segments字段,直接采用transient volatile HashEntry<K,V>[] table保存数据,
采用table数组元素作为锁,从而实现了对每一行数据进行加锁,进一步减少并发冲突的概率。
(2) 把Table数组+单向链表的数据结构 变成为 Table数组 + 单向链表 + 红黑树的结构。
注: 当链表长度超过8以后,单向链表变成了红黑树; 在哈希表扩容时,如果发现链表长度小于 6,则会由红黑树重新退化为链表。
相关参考:
[1] 深入学习Java集合之ConcurrentHashMap的实现原理(jdk1.7与1.8)
https://blog.csdn.net/J080624/article/details/86838129
[2] ConCurrentHashMap 在 jdk1.8
https://blog.csdn.net/bigtree_3721/article/details/84255655
3.Set
HashSet
1)HashSet由哈希表(实际上是一个HashMap实例)支持,不保证set的迭代顺序,并允许使用null元素。
2)基于HashMap实现,API也是对HashMap的行为进行了封装,可参考HashMap
相关参考:深入Java集合学习系列:HashSet的实现原理:
https://zhangshixi.iteye.com/blog/673143
LinkedHashSet
继承与HashSet、又基于LinkedHashMap来实现的(主要通过传递参数调用父类的构造函数实现)。LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承与HashSet,其所有的方法操作上又与HashSet相同。源码内部主要是四个不同的构造函数。
相关参考:深入Java集合学习系列:LinkedHashSet的实现原理:
https://zhangshixi.iteye.com/blog/673319
二、参考文献
[1] List、set、Map的底层实现原理(文章未包含的其余连接出处):
https://blog.csdn.net/xzp_12345/article/details/79251174
[2] Vector原理讲解:https://blog.csdn.net/lipinganq/article/details/78043065
[3] Java中HashMap底层实现原理(JDK1.8)源码分析:
https://blog.csdn.net/tuke_tuke/article/details/51588156
[4] LinkedHashMap图解:https://www.cnblogs.com/whgk/p/6169622.html
[5] 深入学习Java集合之ConcurrentHashMap的实现原理(jdk1.7与1.8):
https://blog.csdn.net/J080624/article/details/86838129
[6] ConCurrentHashMap 在 jdk1.8:
https://blog.csdn.net/bigtree_3721/article/details/84255655
[7] 深入Java集合学习系列: HashSet的实现原理:
https://zhangshixi.iteye.com/blog/673143
[8] 深入Java集合学习系列:LinkedHashSet的实现原理:
https://zhangshixi.iteye.com/blog/673319
Java集合系列(一):List、Map、Set的基本实现原理总结相关推荐
- Java 集合系列14之 Map总结(HashMap, Hashtable, TreeMap, WeakHashMap等使用场景)
概要 学完了Map的全部内容,我们再回头开开Map的框架图. 本章内容包括: 第1部分 Map概括 第2部分 HashMap和Hashtable异同 第3部分 HashMap和WeakHashMap异 ...
- Java 集合系列目录(Category)
Java 集合系列目录(Category) 转自:Java 集合系列目录(Category) 01. Java 集合系列01之 总体框架 02. Java 集合系列02之 Collection架构 0 ...
- 新手菜鸟 Java 集合系列目录(Category)
Java 集合系列01之 总体框架 http://www.cnblogs.com/skywang12345/p/3308498.html (笔记:Java集合是java提供的工具包,包含了常用的数据结 ...
- Java集合系列之四大常用集合(ArrayList、LinkedList、HashSet、HashMap)的用法
Java集合系列之四大常用集合(ArrayList.LinkedList.HashSet.HashMap)的用法 ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是A ...
- Java 集合系列 16 HashSet
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- java集合系列——java集合概述(一)
在JDK中集合是很重要的,学习java那么一定要好好的去了解一下集合的源码以及一些集合实现的思想! 一:集合的UML类图(网上下载的图片) Java集合工具包位置是java.util.* 二:集合工具 ...
- Java 集合系列02之 Collection架构
概要 首先,我们对Collection进行说明.下面先看看Collection的一些框架类的关系图: Java 集合系列02之 Collection架构 Collection是一个接口,它主要的两个分 ...
- Java 集合系列06: Vector深入解析
戳上面的蓝字关注我们哦! 精彩内容 精选java等全套视频教程 精选java电子图书 大数据视频教程精选 java项目练习精选 概论 这是接着以前的文章分享的,这里给出以前的文章的连接,供小伙伴们回顾 ...
- Java 集合系列(一)
Java集合系列文章将以思维导图为主要形式来展示知识点,让零碎的知识形成体系. 这篇文章主要介绍的是[Java 集合的基本知识],即Java 集合简介. 毕业出来一直使用 PHP 进行开发,对于大学所 ...
- 深入Java集合系列之五:PriorityQueue
转载自 深入Java集合系列之五:PriorityQueue 前言 今天继续来分析一下PriorityQueue的源码实现,实际上在Java集合框架中,还有ArrayDeque(一种双端队列),这里 ...
最新文章
- 综述:NLP中的深度学习优势
- 日本“女机器人”畅销全球,有三个地方最吸引人,网友:想拥有
- 山东大学和哈工大的教师招聘条件对比,心里要有点数
- 设计模式(Design Pattern)
- Flutter 之 StatefulWidget和StatelessWidget
- VS2010调试小技巧
- java 异常处理 简书_Java基础知识8-异常处理
- opencv-api minEnclosingCircle
- 【编程开发】 C与C++中的关于函数指针的强制类型转换与指针函数的关系
- solr的索引库配置
- java中handler机制_自己动手撸一个Handler,让你彻底搞懂Handler机制,揍吻你服不服?...
- 设计模式之观察者模式(Java实现)
- Pandas读取excel数据——pearson相关性分析
- [Constraints 18-5210] No constraints selected for write.
- 由frankmocap得到的.pkl文件转为.bvh或者.fbx
- 网络发现自动关闭不能启用、无法启用文件和打印共享的解决办法
- mysql报1142错误
- python情人节之玫瑰花与表白方式,用python画一朵玫瑰花,拿去表白趴
- LiteOS 消息队列
- 计算机二级报名时间2020年12月江苏省,2020年12月计算机二级考试报名时间及考试安排...
热门文章
- stm32时钟问题简单介绍
- 我在atcoder打比赛
- OA系统以项目管理为中心,为会计事务所打造内外协同一体化平台
- nfsd linux是什么进程,如何从NFS启动Linux及原理
- 计算机高中期末总结作文,期末考试总结作文(精选5篇)
- Filament介绍
- 在计算机语言中go是什么意思,golang中的断言是什么意思
- 【数据库数据恢复】华为云mysql数据库数据被delete的数据恢复案例
- MySQL inet aton函数_MySQL INET_ATON()用法及代码示例
- C-Kermit在linux 下的安装和使用