首页 > 编程语言 >Java源码解析-重点集合框架篇

Java源码解析-重点集合框架篇

时间:2023-08-12 11:07:09浏览次数:40  
标签:解析 4.1 ArrayList 源码 数组 集合 Java 数据结构



Java 源码解析,集合篇

  • 一:故事背景
  • 二:数据结构
  • 2.1 线性结构
  • 2.2 非线性结构
  • 三:集合分类
  • 3.1 结构图
  • 四:详细分析
  • 4.1 List
  • 4.1.1 ArrayList
  • 4.1.1.1 底层结构
  • 4.1.1.2 主要特点
  • 4.1.2 LinkedList
  • 4.1.2.1 底层结构
  • 4.1.2.2 主要特点
  • 4.1.3 Vector和Stack
  • 4.1.3.1 Vector
  • 4.1.3.1 Stack
  • 五:总结提升


一:故事背景

本文讲解的源码如未经特殊说明,均JDK1.8为准

  • 不知道大家是否听过这么一句话。程序=算法+数据结构。算法指的是解决问题或者指定任务的步骤和规则的有序集合。而数据结构指的是组织和存储数据的方式。
  • 大家可能学过数据结构,可能也经常会使用Java中的集合类。可这些集合类的源码,你真的研究过吗?这篇文章会带着你去学习Java中常用的集合类。从宏观到微观的方式,从使用到源码的方式,带你深入理解Java各个集合类的源码,让你不仅能用集合类,更能用好,能自己去创造集合类。

二:数据结构

想要理解Java中集合类底层使用的数据结构,就要先了解有什么数据结构。本篇文章我们不多做解释,将常见数据结构以及概念罗列,为我们下面分析Java集合源码做铺垫。
我将数据结构分为了两类,分别是线性结构和非线性结构。

2.1 线性结构

线性结构是一种简单的数据结构,其中数据元素之间存在一对一的关系,即每个元素有且只有一个直接前驱和一个直接后继元素,除了第一个元素没有前驱,最后一个元素没有后继。

  • 数组(Array):一组连续存储的数据元素,通过索引访问元素,具有固定大小。
  • 链表(Linked List):由节点组成的数据结构,每个节点包含数据和指向下一个节点的引用。
  • 栈(Stack):一种具有后进先出(Last-In-First-Out,LIFO)特性的数据结构,只能在栈顶进行插入和删除操作。
  • 队列(Queue):一种具有先进先出(First-In-First-Out,FIFO)特性的数据结构,只能在队列的一端插入,在另一端删除。

2.2 非线性结构

非线性结构是指数据元素之间存在多对多的关系,即一个元素可以有多个前驱和后继元素,或者存在层次关系,不像线性结构那样简单的一维排列。

  • 树(Tree):由节点组成的层次结构,每个节点可以有多个子节点,但每个节点只有一个父节点。
  • 图(Graph):由节点(顶点)和边组成,节点之间的关系可以是任意的,可以是双向的,形成复杂的网络结构。
  • 堆(Heap):一种特殊的树结构,常用于优先队列的实现,有最大堆和最小堆两种形式。

三:集合分类

上文讲了常见的数据结构有这么多,那么Java中的集合类都有哪些呢?每个类使用了那种,那几种数据结构呢?今天我们就一起来盘一盘。

3.1 结构图

Java源码解析-重点集合框架篇_数组


Java集合框架主要分为了两类:

  • 以键值对为首的Map类型,其中典型代表为 HashMap
  • 以Collection(收集、聚集)结构为首的。主要有List、Set、Queue、组成。其中List典型代表为 ArrayList和LinkedList、Set代表为HashSet、Queue代表为双端队列ArrayDeque与优先级队列PriorityQueue

四:详细分析

其实这些集合类主要的功能就是用来盛放数据。既然是用来盛放数据那就好办了。

  • 应用层面:我们可以在 增、删、改、查、的四个角度,分析这些不同。
  • 底层层面:我们可以结合数据结构,分析不同的集合类使用的数据结构,结合这些结构的特点,分析这些不同集合类的效率。
    接下来的讲解中,我们不会对各个集合类的增删改查的用法多做研究,而是主要从数据结构与主要特点两个方面进行讲解,更多的从源码、从设计的角度去学习这些集合类。

4.1 List

List 的特点是存取有序,可以存放重复的元素,可以用下标对元素进行操作。

4.1.1 ArrayList

4.1.1.1 底层结构

ArrayList的底层是由数组进行实现的,其内部维护了一个Object类型的数组,数据实际是存在此数组内。

无参构造:

Java源码解析-重点集合框架篇_数据结构_02


这里的elementData就是用来存储数据的底层数组:

Java源码解析-重点集合框架篇_开发语言_03


DEFAULTCAPACITY_EMPTY_ELEMENTDATA是初始化数组的时候的默认值,默认是空。

Java源码解析-重点集合框架篇_数据_04


这里大家可能有点小疑问,不对啊,之前我听说ArrayList的默认容量是10,怎么你这里说是空呢。这里就要提到其另外一个特点:

ArrayList是懒加载的,在第一次进行插入数据的时候,才会去开辟空间:

Java源码解析-重点集合框架篇_数据_05


具体怎么扩容,我们放在下面主要特点里去分析。

4.1.1.2 主要特点
  • 底层由数组实现,支持随机存取(通过下标直接存取)
    上文我们已经看了ArrayList底层的数组,数组的特点就是支持随机存取,取出数据的时间复杂度为O1。这里我们可以看看ArrayList的获取数据的方法:
  • Java源码解析-重点集合框架篇_数组_06

  • 从尾部插入删除元素最快,中间插入删除较慢,头部插入删除最慢。
    这个特点也与数组的特点有关,由于数组是按照顺序存储的,所以在插入或者删除数据的时候,必须要将插入或者删除位置之后的数组进行移动。数组长度固定的情况下,操作的数组越靠前,需要移动的数据就越多。
  • 内部数组容量不足时会自动扩容,元素量非常大的时候,效率较低。
    自动扩容机制,是ArrayList的一个重要特点。每次插入数据的时候都会去检查是否需要扩容,并且扩容为原来容量的1.5倍。
  • Java源码解析-重点集合框架篇_数据结构_07

  • 我们主要看检查是否需要扩容这部分
  • Java源码解析-重点集合框架篇_java_08

  • calculateCapacity方法内部,就是用来检查当前elementData 是否为空,决定是不是要设置为初始容量,这里验证了我们上文所说,只有在第一次Add的时候才会进行实际创建空间。
  • Java源码解析-重点集合框架篇_开发语言_09

  • 判断是否需要扩容以及扩容的详细逻辑:
  • Java源码解析-重点集合框架篇_java_10


  • Java源码解析-重点集合框架篇_java_11

4.1.2 LinkedList

4.1.2.1 底层结构

LinkedList的底层是一个双向链表结构。通过前后指针维护数据之间的相互关系。其是通过一个内部类进行实现的,内部类里存放了具体的数据,并且维护了前后指针。

Java源码解析-重点集合框架篇_数据_12

4.1.2.2 主要特点
  • 双向链表结构,无法随机存取,只能从一端开始遍历
    双向链表的结构,我们上文已经讲过了,在数据上增加前后指针,使得可以通过指针相互找到。这样的话,在计算机里进行存储就无需逻辑顺序与物理顺序一致。无法随机存取。链表想要在拿到指定位置的数据的话,必须要通过指针进行遍历,找到对应数据所在位置。
  • Java源码解析-重点集合框架篇_数组_13


  • Java源码解析-重点集合框架篇_java_14

  • 这里LinkedList做了一个优化,传入索引之后,其不会直接从头开始遍历,而是判断其是存在于前半区,还是后半区。如果在前半区就从前半部分向后开始遍历,后半区从后半区向前遍历。也就是说LinkedList查找在中间部分的数据效率最低
  • 任意位置插入和删除元素非常方便,只需改变应用即可
    需要注意的是,我们这里说的任意位置,是在确定位置的基础上的,找到对应位置,还是无法避免循环。但是与ArrayList相比,LinkedList找到之后,只需要调整前后指针,替换数据即可,不涉及到数据的批量移动。
  • Java源码解析-重点集合框架篇_java_15


  • Java源码解析-重点集合框架篇_开发语言_16

  • 找到数据之后,调整指针与具体数据即可。
  • 需要更多的空间存储上一个节点和下一个节点的引用
    这个就比较容易理解了,因为LinkedList增加了前后指针,指向前后的数据,这些指针会占用额外的存储空间。正是这些指针体现了链表的这种特性。

4.1.3 Vector和Stack

4.1.3.1 Vector

List 的实现类还有一个 Vector,是一个元老级的类,比 ArrayList 出现得更早。ArrayList 和 Vector 非常相似,只不过 Vector 是线程安全的,像 get、set、add 这些方法都加了 synchronized 关键字,因为synchronized锁属于重量级锁,会阻塞其它线程,导致执行执行效率会比较低,所以现在已经很少用了

Java源码解析-重点集合框架篇_数组_17

4.1.3.1 Stack

Stack 是 Vector 的一个子类,本质上也是由动态数组实现的,只不过还实现了先进后出的功能(在 get、set、add 方法的基础上追加了 pop「返回并移除栈顶的元素」、peek「只返回栈顶元素」等方法),所以叫栈。

Java源码解析-重点集合框架篇_数据结构_18


这些我们就不在深入探讨。在实际项目的使用中,如何设计到并发情况下的线程安全问题,关于List,Java提供了线程安全的并发集合容器类CopyOnWriteArrayList。关于这部分,我会出一个详细文章与锁相结合进行讲解,总结。

五:总结提升

本文讲解了重点的集合框架,从源码的层面和数据结构的层面进行了详细分析,通过本文的学习,希望大家对集合框架有一个细致的了解。接下来我会更新常用的并发容器,结合多线程的知识进行分析。


标签:解析,4.1,ArrayList,源码,数组,集合,Java,数据结构
From: https://blog.51cto.com/u_15854472/7056850

相关文章

  • 欢迎大家加入JAVA技术开发讨论
    最近加了一些java的开发群,感觉每个群的技术氛围都不浓厚,很多问题出来后,根本没人理会。想现在建立一个技术氛围浓厚的java技术问答群,欢迎有兴趣的同学加入。近期也汇总了一些觉得不错的资料,欢迎大家一起进步学习!注:本群不收费,也不做广告推广,仅技术交流。加群方式:点击链接获......
  • 精细解析中文公司名称:智能分词工具助力地名、品牌名、行业词和后缀提取
    精细解析中文公司名称:智能分词工具助力地名、品牌名、行业词和后缀提取中文公司名称分词工具,支持公司名称中的地名,品牌名(主词),行业词,公司名后缀提取。对公司名文本解析,识别并提取地名(place)、品牌名(brand)、行业词(trade)、公司名后缀词(suffix)。[x]补充中国三级地名,优化地名......
  • Java学习笔记(八)
    6.3 多态6.3.1 多态的概念1、什么是多态?多态:多种形态,多种类型的形式两个角度:(1)一个父类的变量,可以赋值给它各种子类的对象换句话说,一个父类的变量,可以在运行时体现为多种不同的子类对象==>编译时都是父类类型的变量,运行时是各种子类的对象类型(2)一个子类对象,可以赋值给不同......
  • 精细解析中文公司名称:智能分词工具助力地名、品牌名、行业词和后缀提取
    精细解析中文公司名称:智能分词工具助力地名、品牌名、行业词和后缀提取中文公司名称分词工具,支持公司名称中的地名,品牌名(主词),行业词,公司名后缀提取。对公司名文本解析,识别并提取地名(place)、品牌名(brand)、行业词(trade)、公司名后缀词(suffix)。补充中国三级地名,优化地名提......
  • java之手搓简单ORM框架--SQL的DELETE
    1.手搓简单SQL增删改查框架-删除1.1创建简单类,并使用泛型类,这里可能使用到之间写的三篇知识的内容,如果不了解的小伙伴可以去java高级之泛型java高级之映射java高级之反射当然,前提是必须要把数据库相关连接弄好,这里会专门出一篇java之jdbc现在咱们继续手搓框架开始叭!1.2前......
  • Java 图片、文件 Base64 互转
    Java图片、文件Base64互转packagecom.thoth.his.base.util;importjava.io.FileInputStream;importjava.io.FileOutputStream;importjava.io.IOException;importjava.util.Base64;publicclassImageUtil{publicstaticStringFileToBase64(StringfilePath)......
  • java之手搓简单ORM框架--SQL的UPDATA
    1.手搓简单SQL增删改查框架-更改1.1创建简单类,并使用泛型类,这里可能使用到之间写的三篇知识的内容,如果不了解的小伙伴可以去java高级之泛型java高级之映射java高级之反射当然,前提是必须要把数据库相关连接弄好,这里会专门出一篇java之jdbc现在咱们继续手搓框架开始叭!由于上......
  • Javascript 面向对象编程
    avascript是一个类C的语言,他的面向对象的东西相对于C++/Java比较奇怪,但是其的确相当的强大,在 Todd同学的“对象的消息模型”一文中我们已经可以看到一些端倪了。这两天有个前同事总在问我Javascript面向对象的东西,所以,索性写篇文章让他看去吧,这里这篇文章主要想从一个整体的角度......
  • Java 观察者模式的浅析
    简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象。这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者对象能够自动更新。 观察者模式的结构 观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(P......
  • 认识Javascript数组
    1.认识数组 数组就是某类数据的集合,数据类型可以是整型、字符串、甚至是对象Javascript不支持多维数组,但是因为数组里面可以包含对象(数组也是一个对象),所以数组可以通过相互嵌套实现类似多维数组的功能 1.1定义数组声明有10个元素的数组vara=newArray(10此时为a已经......