JAVASE进阶:Collection高级(2)——源码剖析ArrayList、LinkedList、迭代器

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:JAVASE进阶:Collection高级(1)——源码分析contains方法、lambda遍历集合
📚订阅专栏:JAVASE进阶
希望文章对你们有所帮助

ArrayList的底层其实还是比较复杂的,如果你去尝试阅读源码的话,但是这又是面试常考的问题,网上有些面经会说当创建ArrayList的时候会在底层创建长度为10的数组,后续会以1.5倍扩容,但是实际上这既不完整,也不准确。因为ArrayList除了用add方法添加元素,还有用addAll方法添加元素。
在这里剖析一下ArrayList,另外剖析一下LinkedList和迭代器的底层。

源码剖析ArrayList、LinkedList

  • ArrayList
    • 原理
    • 源码剖析ArrayList
  • LinkedList
    • LinkedList方法
    • 源码剖析LinkedList
  • 源码剖析迭代器

ArrayList

原理

新手还是先大致讲解一下原理有个印象再去看源码会比较好:

1、利用空参创建的集合,在底层创建一个默认长度为0的数组elementData,并用size=0记录元素个数/元素下次存入位置
2、添加第一个元素时,底层会创建一个新的长度为10的数组,把元素添加进去,size=1
3、存满时,将会扩容1.5倍(其实就是直接再创建一个长度15的数组并把之前数组的元素拷贝进来)
4、若一次添加了多个元素,扩容1.5倍还是放不下,则创建新数组的长度以实际为准

注意点:

1、创建ArrayList的时候底层默认长度为0,添加第一个元素时才会创建出长度为10的数组
2、不是每次存满都扩容1.5倍,因为ArrayList添加元素的方法还有addAll,添加元素过于多就要以实际为准

源码剖析ArrayList

1、Ctrl+N输入ArrayList:
在这里插入图片描述
2、进入后就是ArrayList的空参构造,定位一下DEFAULTCAPACITY_EMPTY_ELEMENTDATA可以发现其一开始创建的确实是空集合,并且size初始值为0:
在这里插入图片描述
在这里插入图片描述
3、Alt+7找到这个类下面的所有成员变量、方法:
在这里插入图片描述
4、右边栏点击add方法,可以看到它又调用了另一个add方法,传入3个参数(当前要添加的元素、集合底层的数组名、集合长度/当前元素应存入的位置):
在这里插入图片描述
5、跟踪这个add方法,可以看到,在添加元素之前会先判断这个容器满了没有,如果满了就会调用grow()函数扩容,然后再增加元素并更新size。
在这里插入图片描述
6、跟踪grow()方法,它会将size+1传入调用另一个grow做扩容,所以当添加了第一个元素的时候,方法体就是return grow(1)
在这里插入图片描述
7、接着跟踪grow,可以看到函数体先记录了原来数组的老容量,然后进行逻辑判断,若是第一次添加元素,老容量还是0,因此会走else:
先比较了DEFAULT_CAPACITY(10)和minCapacity谁更大,若minCapacity更大则以此为标准,但是由于这里是用add方法而不是addAll方法批量添加,在这里显然是创建了长度为10的数组:
在这里插入图片描述
8、下一次走到该扩容函数的时候,长度是已经大于10了,参数符合if条件,此时oldCapacity=10,minCapacity=11,进入if条件,调用了newLength方法去计算新容量的大小,传入的参数为(老容量,最小扩容长度、老容量/2)
在这里插入图片描述
9、跟踪进入newLength方法,minGrowth和prefGrowth可以视为至少要新增的容量大小默认新增容量大小,取最大值后加上oldLegth,默认的情况即为老容量 + 老容量/2 = 1.5 * 老容量,若minGrowth更大,说明默认的1.5倍扩容还是不够大,这时候容量大小就需要以实际长度为准了,这种情况会出现在ArrayList的addAll函数中:
在这里插入图片描述
10、若不满足if情况,则说明此时超过了限定的大小,就需要用hugeLength函数进行处理,跟踪查看该函数,基本上只会执行else if,返回最大限定值:
在这里插入图片描述
至此,底层源码剖析完毕,其实这部分的原理跟之前的StringBuilder有点像,只不过StringBuilder一创建的默认长度就是16,扩容的时候是以原容量 * 2 + 2的方式进行的,也同时拥有grow()方法中的预防机制即插入元素数量过多,导致长度超过扩容后大小,则容量以实际长度为准,所以阅读源码起来感觉很熟悉。

LinkedList

LinkedList方法

LinkedList底层数据结构是双向链表,查询慢但是增删快,操作首尾元素的速度极快。
每一个结点都有3个部分:前一个结点地址值、当前结点的value、后一个结点的地址值。LinkedList本身就多了很多直接操作首尾元素的特有API。

函数名
public void addFirst(E e)
public void addLast(E e)
public E getFirst()
public E getLast()
public E removeFirst()
public E removeLast()

这些方法全部都是针对首尾的,但是List类都是具有根据索引添加、修改和删除元素的操作的,上面的一些操作相对使用的会比较少。

源码剖析LinkedList

1、Ctrl+N选中LinkedList函数,进入:
在这里插入图片描述
2、查看LinkedList中的内部类Node,这就表示了链表中的每个结点:
在这里插入图片描述
3、找到add方法,其调用了addLast函数,前面讲过addLast是专门封装的给LinkedList操作尾部的API:
在这里插入图片描述
4、跟踪LinkedList,可以看出,LinkedList除了插入元素的时候需要把之前末尾结点中的next赋值新增结点,把新增结点的pre赋值为前一个尾结点,还单独记录了头结点和尾结点的位置,其实就是头插法+尾插法
在这里插入图片描述

源码剖析迭代器

一般是这么使用迭代器的:

ArrayList<String> list = new ArrayList<>();
Iterator<String> it = new list.Iterator();
while(it.hasNext()){
	String str = it.next();
	System.out.println(str);
}

接下来跟踪器源码:
1、跟踪Iterator方法,其底层是创建了迭代器对象(Itr)并返回:
在这里插入图片描述
2、跟踪进入Itr,其实它就是一个ArrayList的内部类而已(我们创建的迭代器就是ArrayList对象的迭代器):
(1)cursor表示游标,也就是迭代器中的指针,空参构造默认初始化为0,因此迭代器对象创建后,指针默认指向0索引
(2)lastRet表示之前操作的索引的位置
(3)expectedModCount与并发修改异常有关系
(4)hasNext判断是否有下一个元素(迭代完了没有)
(5)next会获取当前元素并且将指针移动一次
(6)checkForComodification是一种安全性检测
在这里插入图片描述
3、跟踪进入checkForComodification方法,其中modCount变量,这个变量的意思是集合变化的次数,因为删除、修改和添加元素都会使得modCount+1。
这个函数体中先判断当前集合中最新的变化次数和一开始记录的变化次数是否相同,不相同就说明出现了并发修改,此时会报并发修改异常。
在这里插入图片描述
因此,无论我们使用迭代器、增强for还是lambda表达式(底层遍历方式都是迭代器),遍历集合的过程中,不要去使用集合中的方法去增加或删除元素。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java学习-内部类

内部类概述 1.成员内部类 注意&#xff1a; 2.静态内部类 3.局部内部类&#xff08;看看就行&#xff09; 4.匿名内部类 应用场景&#xff1a;通常作为一个参数传给方法 Eg.小猫和小狗都参加游泳比赛

图解支付-金融级密钥管理系统:构建支付系统的安全基石

经常在网上看到某某公司几千万的个人敏感信息被泄露&#xff0c;这要是放在持牌的支付公司&#xff0c;可能就是一个非常大的麻烦&#xff0c;不但会失去用户的信任&#xff0c;而且可能会被吊销牌照。而现实情况是很多公司的技术研发人员并没有足够深的安全架构经验来设计一套…

使用WPS制作三线表

点击边框和底纹点击1、2、3、4并且应用于表格点击确定 再次选中表格点击右键表格属性选择边框和底纹 选中表格第一行右键点击表格属性选择边框和底纹 如果表格中存在虚线

用户访问一个购物网站时TCP/IP五层参考模型中每一层的功能

当用户访问一个购物网站时&#xff0c;网络上的每一层都会涉及不同的协议&#xff0c;具体网络模型如下图所示。 以下是每个网络层及其相关的协议示例&#xff1a; 物理层&#xff1a;负责将比特流传输到物理媒介上&#xff0c;例如电缆或无线信号。所以在物理层&#xff0c;可…

调用其他数据库,事务回滚

1、定时 JDBC 的事务 2、事务提交 3、事务回滚 样例 Transactional(propagation Propagation.REQUIRES_NEW)RequestMapping(value "/ix_work_order", method RequestMethod.POST, consumes MediaType.APPLICATION_JSON_VALUE,produces MediaType.APPLICATION_…

spring boot3x登录开发-上(整合jwt)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途。 目录 前置条件 jwt简介 导依赖 编写jwt工具类 1.配置项直接嵌入代码&#xff0c;通过类名.静态方法使用 2.配置项写到…

大数据 - Spark系列《三》- 加载各种数据源创建RDD

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 目录 3.1&#x1f9c0;加载文件(本地) 1. 加载本地文件路径 &#x1f32e;使用te…

让IIS支持SSE (Server Sent Events)

本文只探讨IISPython网站的情况&#xff0c;对于asp.net也应该不用这么麻烦。 先上结论&#xff1a;用反向代理&#xff1a; IIS URL Rewrite waitress Waitress是一个纯python编写独立的WSGI服务器&#xff0c;功能比Gunicorn弱一些&#xff0c;但可以运行在windows平台上&…

基于springboot智慧养老平台源码和论文

首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…

牛客周赛 Round 31

D. 思路&#xff1a;使用map构造两个链表。 #include <bits/stdc.h> using namespace std;map<int,int> l,r; int main() {int q;cin>>q;int op-1e9-1;int ed1e91;r[op]ed;l[ed]op;while(q--){int a;cin>>a;if(a1){int x,y;cin>>x>>y;int…

echarts使用之饼图(四)

1 基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible" cont…

【Elasticsearch】从入门到精通

目前java常见的针对大数据存储的方案并不多&#xff0c;常见的就是mysql的分库分表、es存储 这里偏向es存储方案&#xff0c;es不同的版本之间其实差异还挺大的&#xff0c;本篇博文版本Elasticsearch 7.14.0 Springboot整合Easy-Es Easy-Es官方文档 Elasticsearch的初步认识 …

【MATLAB源码-第135期】基于matlab的变色龙群优化算法CSA)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 变色龙群优化算法&#xff08;Chameleon Swarm Algorithm&#xff0c;CSA&#xff09;是一种新颖的群体智能优化算法&#xff0c;受到自然界中变色龙捕食和社交行为的启发。变色龙以其独特的适应能力而著称&#xff0c;能够根…

【vue3学习P5-P10】vue3语法;vue响应式实现

0、vue2和vue3对比 框架版本API方式双向绑定原理domFragmentsTree-Shakingvue2选项式API&#xff08;Options API&#xff09;基于Object.defineProperty&#xff08;监听&#xff09;实现&#xff0c;不能双向绑定对象类型的数据【通过Object.defineProperty里面的set和get做…

【Linux网络编程三】Udp套接字编程网络应用场景

【Linux网络编程三】Udp套接字编程网络应用场景 应用场景一&#xff1a;远程命令执行应用场景二&#xff1a;与Windos端相互通信应用场景三&#xff1a;简单聊天1.多线程化2.输入输出分开 应用场景一&#xff1a;远程命令执行 简单的服务器上一篇已经完成&#xff0c;接下来我…

Java项目管理01-Maven基础

一、Maven的常用命令和生命周期 1.Maven的常用命令使用方式 complie&#xff1a;编译&#xff0c;将java文件编译为class字节码文件 clean&#xff1a;清理&#xff0c;删除字节码文件 test&#xff1a;测试&#xff0c;运行项目中的test类 package&#xff1a;打包&#x…

高斯消去法 | LU分解 | PA=LU分解(MatLab)

一、问题描述 利用高斯消去法&#xff0c;LU 分解及PALU 分解求解非线性方程组。 二、实验目的 掌握高斯消去法、LU 分解、PALU 分解的算法原理&#xff1b;编写代码实现利用高斯消去法、LU 分解、PALU 分解来求解线性方程组。 三、实验内容及要求 1. 利用顺序高斯消去法求…

计算机毕业设计社区居民服务管理系统SSM

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; vue mybatis Maven mysql5.7或8.0等等组成&#xff0c;B…

Redis——SpringBoot整合Redis实战

1、基本配置 1.1、引入依赖 首先&#xff0c;建立Maven项目&#xff0c;在Maven项目中引入pom.xml文件&#xff1a; <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> &l…

HTML5和CSS3强化知识总结

HTML5的新特性 HTML5的新增特性主要是针对于以前的不足&#xff0c;增一些新的标签、新的表单和新的表单属性等。这些新特性都有兼容性问题&#xff0c;基本是IE9以上版本的浏览器才支持&#xff0c;如果不考虑兼容性问题&#xff0c;可以大量使用这些新特性。 HTML5新增的语义…