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

news2024/7/7 16:54:11

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集合框架主要分为了两类:

  • 以键值对为首的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类型的数组,数据实际是存在此数组内。
无参构造:
在这里插入图片描述
这里的elementData就是用来存储数据的底层数组:
在这里插入图片描述
DEFAULTCAPACITY_EMPTY_ELEMENTDATA是初始化数组的时候的默认值,默认是空。
在这里插入图片描述
这里大家可能有点小疑问,不对啊,之前我听说ArrayList的默认容量是10,怎么你这里说是空呢。这里就要提到其另外一个特点:
ArrayList是懒加载的,在第一次进行插入数据的时候,才会去开辟空间:
在这里插入图片描述
具体怎么扩容,我们放在下面主要特点里去分析。

4.1.1.2 主要特点

  • 底层由数组实现,支持随机存取(通过下标直接存取)
    上文我们已经看了ArrayList底层的数组,数组的特点就是支持随机存取,取出数据的时间复杂度为O1。这里我们可以看看ArrayList的获取数据的方法:
    在这里插入图片描述

  • 从尾部插入删除元素最快,中间插入删除较慢,头部插入删除最慢。
    这个特点也与数组的特点有关,由于数组是按照顺序存储的,所以在插入或者删除数据的时候,必须要将插入或者删除位置之后的数组进行移动。数组长度固定的情况下,操作的数组越靠前,需要移动的数据就越多。

  • 内部数组容量不足时会自动扩容,元素量非常大的时候,效率较低。
    自动扩容机制,是ArrayList的一个重要特点。每次插入数据的时候都会去检查是否需要扩容,并且扩容为原来容量的1.5倍。
    在这里插入图片描述
    我们主要看检查是否需要扩容这部分
    在这里插入图片描述calculateCapacity方法内部,就是用来检查当前elementData 是否为空,决定是不是要设置为初始容量,这里验证了我们上文所说,只有在第一次Add的时候才会进行实际创建空间。
    在这里插入图片描述
    判断是否需要扩容以及扩容的详细逻辑:
    在这里插入图片描述
    在这里插入图片描述

4.1.2 LinkedList

4.1.2.1 底层结构

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

4.1.2.2 主要特点

  • 双向链表结构,无法随机存取,只能从一端开始遍历
    双向链表的结构,我们上文已经讲过了,在数据上增加前后指针,使得可以通过指针相互找到。这样的话,在计算机里进行存储就无需逻辑顺序与物理顺序一致。无法随机存取。链表想要在拿到指定位置的数据的话,必须要通过指针进行遍历,找到对应数据所在位置。
    在这里插入图片描述
    在这里插入图片描述
    这里LinkedList做了一个优化,传入索引之后,其不会直接从头开始遍历,而是判断其是存在于前半区,还是后半区。如果在前半区就从前半部分向后开始遍历,后半区从后半区向前遍历。也就是说LinkedList查找在中间部分的数据效率最低

  • 任意位置插入和删除元素非常方便,只需改变应用即可
    需要注意的是,我们这里说的任意位置,是在确定位置的基础上的,找到对应位置,还是无法避免循环。但是与ArrayList相比,LinkedList找到之后,只需要调整前后指针,替换数据即可,不涉及到数据的批量移动。
    在这里插入图片描述
    在这里插入图片描述
    找到数据之后,调整指针与具体数据即可。

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

4.1.3 Vector和Stack

4.1.3.1 Vector

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

4.1.3.1 Stack

Stack 是 Vector 的一个子类,本质上也是由动态数组实现的,只不过还实现了先进后出的功能(在 get、set、add 方法的基础上追加了 pop「返回并移除栈顶的元素」、peek「只返回栈顶元素」等方法),所以叫栈。
在这里插入图片描述
这些我们就不在深入探讨。在实际项目的使用中,如何设计到并发情况下的线程安全问题,关于List,Java提供了线程安全的并发集合容器类CopyOnWriteArrayList。关于这部分,我会出一个详细文章与锁相结合进行讲解,总结。

五:总结提升

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/850944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAM 大模型Colab快速上手【Segment Anything Model】

Google Colab 是一个基于云的 Jupyter 笔记本环境,允许您通过浏览器编写、运行和共享 Python 代码。 它就像 Google 文档,但用于代码。 通过免费版本的 Google Colab,你可以获得带有约 16GPU VRAM 的 Nvidia Tesla T4 GPU,这对于…

2023牛客暑期多校训练营6

参考2023牛客暑期多校训练营6(G、E、C、B、A) - 知乎 (zhihu.com) 纯数学,推式子 从贡献度的角度考虑 首先,当两个子集大小均相同时,才有可能变相同 其次是我们需要先将S和T中的数分别从小到大排个序,然后要变相同花费最小,肯定是对齐的数之间变换,可…

【力扣每日一题】2023.8.8 任意子数组和的绝对值的最大值

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目给我们一个数组,让我们找出它的绝对值最大的子数组的和。 这边的子数组是要求连续的,让我们找出一个元素之和…

Cadvisor+InfluxDB+Grafan+Prometheus(详解)

目录 一、CadvisorInfluxDBGrafan案例概述 (一)Cadvisor Cadvisor 产品特点: (二)InfluxDB InfluxDB应用场景: InfluxDB主要功能: InfluxDB主要特点: (三&#…

【mock安装时报错】

node版本需要大于16 切换>16的版本即可 建议使用 nvm进行 node版本状态管理 可参考另一篇文章 nvm多版本管理方案

2021年09月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 取整除的运算符是? A:/ B:// C: D:** 正确的答案是:B://。 解析:在Python中,取整除的运算符是双斜杠(//)。它执行除法运算并返回结果的整数部分,即向下取整。相比之下,除法运算符(/)返回的是精确的浮点数结…

C语言数组第十课---------------三子棋-------数组经典练手题

作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 🎂 作者介绍: 🎂🎂 🎂…

从0到1搭建uniapp

一、什么是uniapp UniApp是一款基于Vue.js框架的全端开发工具,可以实现同时开发多个平台(包括H5、小程序、APP等)应用的能力。使用UniApp,开发者只需要编写一份代码就可以快速地发布到多个平台,极大地提高了开发效率和…

java实现当前系统时间格式化

import java.text.SimpleDateFormat; import java.util.Date;public class DateTest {public static void main(String[] args) {Date date new Date();System.out.println("当前系统时间:" date);SimpleDateFormat simpleDateFormat new SimpleDateFo…

MySQL 查询语句大全

目录 基础查询 直接查询 AS起别名 去重(复)查询 条件查询 算术运算符查询 逻辑运算符查询 正则表达式查询⭐ 模糊查询 范围查询 是否非空判断查询 排序查询 限制查询(分页查询) 随机查询 分组查询 HAVING 高级查询…

数据结构和算法三(排序)

列表排序 排序类型&#xff1a; 一、冒泡排序&#xff1a; 屏幕录制2023-07-25 13.05.12 def bubble_sort(li):exchangeFalseif len(li)<1:return lifor i in range(len(li)-1):for j in range(len(li)-i-1):if li[j]>li[j1]:li[j],li[j1]li[j1],li[j]print(li)exchangeT…

【数理知识】奇异值分解,从数据的线性变换角度来理解

序号内容1【数理知识】自由度 degree of freedom 及自由度的计算方法2【数理知识】刚体 rigid body 及刚体的运动3【数理知识】刚体基本运动&#xff0c;平动&#xff0c;转动4【数理知识】向量数乘&#xff0c;内积&#xff0c;外积&#xff0c;matlab代码实现5【数理知识】协…

学习电气工程的关键要点

基础知识&#xff1a;学习电路原理、电子器件、电机原理等基础知识。可以通过自学、培训或相关专业课程来学习。 编程技能&#xff1a;掌握一门编程语言&#xff0c;如C语言或MATLAB。电气工程常需要编程来设计和实现控制系统。 自动化控制理论&#xff1a;了解自动化控制系…

Python web实战之Django 的 RESTful API 设计详解

关键词: Python, Web 开发, Django, RESTful API 1 API的一些事儿 1.1 什么是API&#xff1f; API是应用程序编程接口&#xff08;Application Programming Interface&#xff09;的缩写。它是一种定义了不同软件组件之间交互方式的规范。API允许不同的应用程序之间进行通信和…

【LeetCode】数据结构题解(10)[有效的括号]

有效的括号 &#x1f609; 1.题目来源&#x1f440;2.题目描述&#x1f914;3.解题思路&#x1f973;4.代码展示 &#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1…

机器学习笔记:李宏毅ChatGPT Finetune VS Prompt

1 两种大语言模型&#xff1a;GPT VS BERT 2 对于大语言模型的两种不同期待 2.1 “专才” 2.1.1 成为专才的好处 Is ChatGPT A Good Translator? A Preliminary Study 2023 Arxiv 箭头方向指的是从哪个方向往哪个方向翻译 表格里面的数值越大表示翻译的越好 可以发现专门做翻…

vue3 table动态合并,自定义参数合并单元格

<template><div><el-table :data"tableData" :span-method"objectSpanMethod" border:header-cell-style"{ textAlign: center}"><el-table-column prop"area" label"区域" align"center"&g…

如何在页面中嵌入音频和视频?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 嵌入音频⭐ 嵌入视频⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏…

《合成孔径雷达成像算法与实现》Figure3.2

代码参数说明&#xff1a;Sf1为书中公式3.19&#xff0c;Sf2为时域信号快速傅里叶表达式&#xff0c;两种频谱表达式所做出的图可看出其区别 代码如下&#xff1a; clc clear all close all%参数设置 TBP 720; %时间带宽积 T 10e-6; %脉冲持续时间%参数计…

20.5 HTML 媒体

1. video视频标签 video视频标签: 是HTML中用于在网页上嵌入视频的元素.常用的视频标签属性: - src属性: 指定视频文件的URL地址. - controls属性: 用于显示视频播放控件(如播放按钮, 进度条等), 使用户能够控制视频的播放. - width和height: 指定视频的宽度和高度. - autopla…