看完这篇ArrayList,工资直接+10000

Java集合面试核心考点:HashMap与ConcurrentHashMap底层原理全解析 Java集合框架是后端开发与面试中绕不开的基础知识体系,其核心包括List、Map、Set等接口及各类实现。从ArrayList的1.5倍扩容,到HashMap基于数组+链表+红黑树的哈希定位与树化策略,底层原理处处体现时间与空间的权衡。理解这些机制不仅能应对面试官对源码的连环追问,还能指导实际编码中的性能优化。而在高并发场景下,ConcurrentHashMap通过CAS与synchronized实现桶级锁细化,成为线程安全映射的首选方案;同时,遍历时fail-fast机制与modCount检查也提醒开发 阅读详情

前言

ArrayList花Gie猜想应该所有Java的小伙伴都用过,如果还有小伙伴没用过,请文末留言,你放学给我留下来我给你补习补习。本文是集合类讲解的第一篇,选择了一个相对比较简单、大家又比较熟悉的ArrayList开篇。集合是Java中非常重要而且基础的内容,因为任何数据必不可少的就是该数据是如何存储的,集合的作用就是以一定的方式组织、存储数据。

正文

狗剩子:花Gie,新系列开启,还有点小激动呀!

毕竟同时肝几个系列,也是有点要老命的,你看我这日渐光亮的头顶,哎,啥也不说了。

狗剩子:…以后省洗发水了你,憋扯犊子了,给我说说学习集合我要注意哪几点吧!

(摸了摸光滑的头顶,若有所思)对于集合,我认为关注的点主要有以下四点:

  • 是否允许空
  • 是否允许重复数据
  • 是否有序,有序的意思是读取数据的顺序和存放数据的顺序是否一致
  • 是否线程安全

狗剩子:可以说下ArrayList怎么用的吗?

首先看一下他的新增元素的方法add(),非常简单,代码如下:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2); 

狗剩子:看着是挺简单的,那就说下新增在底层是怎么实现的吧!

…这么突然的吗,直接肝到原理了,好吧,来来来

add方法的源码来看一下:

image.png

第2行的ensureCapacity方法是扩容用的,占时先不看。底层实际上在调用add方法的时候只是给elementData的某个位置添加了一个数据而已,用一张图表示的话是这样的:

图片

这里需要提醒一下,elementData中存储的应该是堆内存中元素的引用,而不是实际的元素,花Gie这么画图主要是为了小伙伴们理解,只要知道这个问题就好了。

狗剩子:那ensureCapacity这个扩容方法是什么原理呢?

哟呼,狗子今天当了面试官,还知道追问了。那我们先看一下,构造ArrayList的时候,默认的底层数组大小是10:

image.png

既然固定了大小,那底层数组的大小不够了怎么办?狗子都知道那就是扩容,这也就是为什么一直说ArrayList的底层是基于动态数组实现的原因,动态数组的意思就是指底层的数组大小并不是固定的,而是根据添加的元素大小进行一个判断,不够的话就动态扩容,扩容的代码就在ensureCapacity里面:

 private void grow(int minCapacity) {
     //1. 获取数组长度
     int oldCapacity = elementData.length;
     
     //oldCapacity >> 1 相当于除以2
     //2. 新数组容量=原数组容量 * 1.5。
     int newCapacity = oldCapacity + (oldCapacity >> 1);
     
     //3. 如果新的数组容量小于传入的参数要求的最小容量minCapacity,那么新的数组容量以传入的容量参数为准。
     if (newCapacity - minCapacity < 0)
         newCapacity = minCapacity;
     
     //4. 判断新的数组容量newCapacity是否大于数组能容纳的最大元素个数 MAX_ARRAY_SIZE
     if (newCapacity - MAX_ARRAY_SIZE > 0)
         //5.
         newCapacity = hugeCapacity(minCapacity);
     
     //6. 将扩容前数组放进新的扩容后的数组
     elementData = Arrays.copyOf(elementData, newCapacity);
 } 

其中第 5 步hugeCapacity(minCapacity)用于判断传入的参数minCapacity是否大于MAX_ARRAY_SIZE,如果minCapacity大于MAX_ARRAY_SIZE,那么newCapacity等于Integer.MAX_VALUE,否者newCapacity等于MAX_ARRAY_SIZE

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
} 

狗剩子:感觉很简单的扩容方式,那为什么要使用这种方式扩容呢?

大佬们定的,我能回答出来怎么扩容的还不够强么,还问为啥,你是十万个为什么嘛。

狗剩子:回答对了工资加五百

这样呀,那这个就好办了。

image.png

我们可以想:

1、如果一次性扩容扩得太大,必然造成内存空间的浪费

2、如果一次性扩容扩得不够,那么下一次扩容的操作必然比较快地会到来,这会降低程序运行效率,要知道扩容还是比较耗费性能的一个操作

所以扩容扩多少,是JDK开发人员在时间、空间上做的一个权衡,提供出来的一个比较合理的数值。最后调用到的是Arrays的copyOf方法,将元素组里面的内容复制到新的数组里面去:

image.png

用一张图来表示就是这样的:

图片

狗剩子:带图示的就很棒,给你一个么么哒,除了顺序添加元素,肯定有按照下标插入的咯

你可真是个机灵鬼,ArrayList的插入操作调用的也是add方法,比如:

List<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
list.add("444");
list.add("555");
list.add("666");
list.add("777");
list.add("888");
list.add(2,"000");
System.out.println(list); 

有一个地方不要搞错了,第10行的add方法的意思是,往第几个下标插入数据,像第10行就是在下标为2的位置插入数据000(注意ArrayList下标从0开始,即list.get(0)的值是111)。看一下运行结果也证明了这一点:

[111, 222, 000, 333, 444, 555, 666, 777, 888] 

还是看一下插入的时候做了什么:

image.png

可以看到插入的时候,先用ensureCapacity方法进行判断是否扩容按照指定位置,然后利用System.arraycopy方法从指定位置开始的所有元素做一个整体的复制,向后移动一个位置,然后指定位置的元素设置为需要插入的元素,完成了一次插入的操作。用图表示这个过程是这样的:

图片

狗剩子:哟~不错哦,那再说说删除元素吧!

ArrayList支持以下两种删除方式:

  • 按照下标删除,即list.remove(1)

  • 按照元素删除,使用方式为list.remove(“111”),如果有多个等值的元素111,也只是会删除匹配的第一个元素

从代码来看,这两种删除方法在ArrayList的实现原理差不多,都是调用的下面一段代码:

image.png

简单概括其实做的事情只有两件:

  1. 把指定元素后面位置的所有元素,利用System.arraycopy方法整体向前移动一个位置

  2. 最后一个位置的元素指定为null,这样让gc可以去回收它

比方现在操作这一段代码:

List<String> list = new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
list.add("444");
list.add("555");
list.add("666");
list.add("777");
list.add("888");
list.remove("3333"); 

用图表示是为:

图片

狗剩子:那你总结一下ArrayList特点呗!

ArrayList应该是小白到大佬都非常常用的集合类,它是一个以数组形式实现的集合,花Gie这里用一张表格先来看一下ArrayList里面有哪些基本的元素:

元 素作 用
private transient Object[] elementData;ArrayList是基于数组的一个实现,elementData就是底层的数组
private int size;ArrayList里面元素的个数,这里要注意一下,size是按照调用add、remove方法的次数进行自增或者自减的,所以add了一个null进入ArrayList,size也会加1

ArrayList属性一览:

属 性结 论
ArrayL ist是否允许空允许
ArrayList是否允许重复数据允许
ArrayList是否有序有序
ArrayList是否线程安全非线程安全

狗剩子:说了那么多,那ArrayList有啥优缺点呀

任何事物都不是完美无瑕的,我们要结合场景合理使用,ArrayList的优点如下:

  1. ArrayList底层以数组实现,是一种随机访问模式,再加上它实现了RandomAccess接口,因此查找也就是get的时候非常快
  2. ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已

不过ArrayList的缺点也十分明显:

  1. 删除元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能

  2. 插入元素的时候,涉及到一次元素复制,如果要复制的元素很多,那么就会比较耗费性能

因此,简单总结就是:ArrayList比较适合顺序添加、随机访问的场景。

拓展部分

狗剩子:这里有个疑问困扰了我好久了呢,为什么ArrayList的elementData是用transient修饰的?

image.png

这个差点超出了我的认知,还好花Gie昨晚看过秘籍宝典。

image.png

我们看一下ArrayList的定义:

image.png

ArrayList实现了Serializable接口,也就是说ArrayList是可以被序列化的,而用transient修饰elementData意味着我不希望elementData数组被序列化。

这一万个草泥马奔腾而过,不能慌?因为序列化ArrayList的时候,elementData未必是满的,比方说elementData有10的大小,但是我只用了其中的3个,那么是否有必要序列化整个elementData呢?显然没有这个必要,因此ArrayList中重写了writeObject方法:

image.png

每次序列化的时候调用这个方法,先调用defaultWriteObject()方法序列化ArrayList中的非transient元素,elementData不去序列化它,然后遍历elementData,只序列化那些有的元素,这样就会有两点好处:

  1. 加快了序列化的速度

  2. 减小了序列化之后的文件大小

总结

ArrayList的重要性大家应该都懂,这里也就不啰嗦了。我们在读源码的时候,其实有很多可以值得我们借鉴,比如elementData使用transient来修饰,学习中需要多思考,把学习到的技术和思想运用到自己实际开发中,学以致用,才能不断强大。

点关注,防走丢

以上就是本期全部内容,如有纰漏之处,请留言指教,非常感谢。我有问题大家随时留言讨论 ,我们下期见🦮。

+++

文章持续更新,可以微信搜一搜 Java开发零到壹 第一时间阅读,并且可以获取面试资料学习视频等,有兴趣的小伙伴欢迎关注,一起学习,一起哈🐮🥃。

原创不易,你怎忍心白嫖,如果你觉得这篇文章对你有点用的话,感谢老铁为本文点个赞、评论或转发一下,因为这将是我输出更多优质文章的动力,感谢!

SWD下载调试接口原理深度剖析 作为ARM嵌入式工程师,下载调试器都应该知道,但你真正了解SWD如何下载调试的么?ARM 芯片通过什么物理接口和什么方式连接完全取决于芯片Debug子系统的架构如何? 阅读详情

相关推荐

Android车载应用开发:Kotlin与Automotive OS深度实践

Android Automotive OS(AAOS)是Google专为车辆设计的操作系统,直接运行于车机硬件,提供完整的车载信息娱乐系统(IVI)。与Android Auto不同,AAOS允许开发者深度集成车辆硬件功能,如空调控制和传感器数据读取,同时遵循严格的驾驶安全规范。Kotlin作为开发语言,具备空安全设计、扩展函数和协程支持等优势,简化了开发流程。开发环境配置包括Android Studio、AAOS模拟器和Gradle配置,核心组件如CarAppService、Screen与模板系统,以及车辆

时小雨的专栏 3445

ArrayList源码分析

前言:作为一个常用的List接口实现类,日常开发过程中使用率非常高,因此有必要对其原理进行分析。 注:本文jdk源码版本为jdk1.8.0_172 1.ArrayList介绍 ArrayList底层数据结构是数组(数组是一组连续的内存空间),默认容量为10,它具有动态扩容的能力,线程不安全,元素可以为null。 笔者在一次使用ArrayList的时候引起了一次线上OOM,分析...

weixin_30692143的博客 234

VMware VSAN 高级参数介绍(测试用)

VSAN 的策略驱动让我们看到了VSAN无穷的潜力,其设计思路相当新颖,在一个基础资源池上使用策略就能实现不同对象的区分服务,而目前没有其他厂家能到VMware这样的高度。 VSAN 呈现给用户配置很简单,但实际上设计及后台比较复杂。笔者无意间发现了VSAN的隐藏高级参数设置,有很多好玩的选项想分享出来。这些参数全部是针对每主机进行设置的。VSAN 中有很多默认设置,这些设置应该都是研发人员多次测试得出的最优值,修改可能导致环境异常,并不建议修改! 目录 参数1:全闪配置下 SSD 写缓存最大.

山水牧羊 2032

初始化ArrayList的两种方法

方式一: ArrayList list = new ArrayList(); String str01 = String(“str01”); String str02 = String(“str02”); list.add(str01); list.add(str02); 方式二: ArrayList list = new ArrayList(){{add(“...

lvjingWn的博客 1309

WSL 相关命令时遇到了 “无法从raw.githubusercontent.com提取分发列表、操作超时

核心问题:国内网络屏蔽raw.githubusercontent.com,导致WSL无法获取发行版列表;最优方案:优先用方案1(手动指定发行版安装),无需改配置,1分钟搞定;永久修复:用方案2(修改hosts),适合需要管理多个WSL发行版的场景;兜底方案:用方案3(手动下载安装包),适配所有网络环境。按以上步骤操作后,你不仅能正常安装WSL,等命令也能正常执行,后续可正常使用WSL搭配Docker Desktop(如切换WSL 2后端),无需再担心网络超时问题。

weixin_39766667的博客 2147

GEE进行Theil-Sen Median斜率估计和Mann-Kendall检验

Python实现Theil-Sen Median斜率估计和Mann-Kendall检验// 定义时间范围//NDVI图像集合// 定义每年的开始和结束日期// 加载NDVI数据集,按日期过滤,并计算最大值.max()}));// 计算Sen斜率并剪裁// 可视化Sen斜率Map.addLayer(senSlope.select('slope'), vis, "Sen斜率 ");// MK检验// 创建一个列表,包含年度NDVI图像的list。

qq_44894692的博客 965

ArrayList的构造函数和Add方法

ArrayList 描述:其实ArrayList本质就是数组.(外带一句LinkList是链表) 数组的特点: 数组存储在内存中是连续的. 由于是连续的所以插入和删除效率就会比较慢(相对链表等)因为插入一个数值,后面的元素都要依次往后移,删除的话后面的元素都会依次往前移. 随意访问数据很快,因为数组是连续的,知道每一个数据的内存地址,可以直接找到给地址的数据。 链表的特点 链表随机访问很慢,因为每次访问一个变量都需要循环从的一个元素开始比遍历 插入和删除很容器,因为链表不涉及到移位,只需要修改节点指

Int_Xu的博客 742

FastBuilding 3DMAX插件:批量生成配楼,让建筑可视化告别手动重复建模

在建筑可视化与城市规划项目中,配楼群是营造城市氛围和方案完整度的关键,但几十上百栋配楼的建模往往成为工期瓶颈。传统复制粘贴或BOX贴图方式无法兼顾真实感与效率。FastBuilding作为一款3DMAX插件,通过参数化生成逻辑,将配楼制作转化为可调控的流水线:设定层高、面宽、窗户密度等参数,即可在视口内实时生成带完整外立面细节的实体模型;支持点选拉框和样条线批量生成两种模式,配合随机种子可快速产出丰富而不失协调的建筑群。该插件不仅面数控制合理,生成模型仍可继续编辑,尤其适合住宅区鸟瞰、规划投标及远景天际线等

weixin_28520495的博客 254

看完这篇ArrayList,工资直接+1000

前言 ArrayList小编猜想应该所有Java的小伙伴都用过,如果还有小伙伴没用过,请文末留言,你放学给我留下来我给你补习补习。本文是集合类讲解的第一篇,选择了一个相对比较简单、大家又比较熟悉的ArrayList开篇。集合是Java中非常重要而且基础的内容,因为任何数据必不可少的就是该数据是如何存储的,集合的作用就是以一定的方式组织、存储数据。 正文 狗剩:小编,新系列开启,还有点小激动呀! 毕竟同时肝几个系列,也是有点要老命的,你看我这日渐光亮的头顶,哎,啥也不说了。 狗剩:…以后省洗发水了你,憋

weixin_57907028的博客 262

Win 11 Fastboot驱动的详细安装教程

Fastboot驱动的详细安装教程

水w的博客 1万+

WinCC 7.5 读取 SQL server2016 中的表格数据

环境 win10 SQL Server 2016 WinCC V7.5 SP2 1 安装SQL Server 2016 2 选择服务器名称 .\WINCC 3 建数据库

skr? 7142

ArrayList的学习

第一篇博客,就从ArrayList开始写起吧(在修士阶段我主要用的的perl和c,博客中我会对三者进行比较,O(∩_∩)O~) ArrayList就是java里面传说中的动态数组,array在分配内存以后array的长度不能被改变。如果想在运行过程中增加内存的话,就要请出arraylist了(O(∩_∩)O~)。 以下部分是转载的:http://www.

小轮子 488

BoT-SORT实战:手把手教你实现BoT-SORT训练和测试

文章目录摘要1、数据准备2、配置BoT-SORT环境2.1、获取代码2.2、创建虚拟环境2.3、安装必要的包2.3.1、安装pytorch2.3.2、安装cython2.3.3、安装Cython-bbox2.3.4、安装faiss2.3.5、安装其他的包3、训练3.1、生成REID数据集3.2、预训练模型3.2.1、ByteTrack预训练模型3.2.2、REID预训练模型3.3、开始训练4、如何更改FASTREID的BackBone?5、测试5.1、测试视频5.2、测试摄像头5.3、多类别测试 摘要 Bo

m0_47867638的博客 2299

ArrayList做的员工薪资管理系统

/** * 公司职员薪水管理系统,有以下功能 * 1,当有新员工时,将加入该管理系统 * 2,根据员工号,显示该员工信息 * 3,可以显示所有员工的信息 * 4,可以修改员工的薪水 * 5,当员工离职时,从该系统中删除该员工 * 6,可以将员工按薪水高低排序(思考) * 7,统计员工的平均工资,最高和最低工资 */ import java.util.ArrayList; import java.u...

qq_39560479的博客 531

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Java:用类实现员工的平均年龄,平均工资和总工资

Java:用类实现员工的平均年龄,平均工资和总工资。

Pluto_ikun的博客 412

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

练习题 02(List 遍历的使用)

(List)编程:创建一个工人类,属性:姓名、年龄、工资,要求如下: (1) 为Worker提供无、有参数的构造方法,属性私有,并提供公开的get/set (2) 创建多个Worker类,存储在List集合中。 (3) 打印输出所有的工人信息。 (4) 计算所有工人的平均工资。 (5) 打印输出姓名中包含 “胡” 的所有工人信息。 (6) 打印输出所有姓 “胡"的工人信息。 (7) 键盘输入一个姓...

qq_37224665的博客 3122

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

04-jdk8 终止 操作

public class Demo8 { public static void main(String[] args) { ArrayList<Employee> lst=new ArrayList<>(); lst.add(new Employee("小王",1000)); lst.add(new Employee("小张",11000)); lst.add(new Employee("小刘",11000...

航行博客 410

list练习题—输入工人信息

1)创建一个List,在List中增加三个工人,基本信息如下: 姓名年龄工资 zhang3183000 li4253500 wang5223200 2)在li4之前插入一个工人,信息为:姓名:zhao6,年龄:24,工资3300 3)删除wang5的信息 4)利用for循环遍历,打印List中所有工人的信息 5)利用迭代遍历 ...

weixin_34383618的博客 1285

【Java基础】· 集合习题详解

目录【往期回顾】答:Collection是集合类的上级接口,继承于他的接口主要有Set 和List.Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作答:Set里的元素是不能重复的,用equals()方法判读两个Set是否相等 equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值答: List,Set是,Map不是答:不对,有相同的hash code答:Arr

麟-小白的博客 1212

第11章_Java集合

Java基础编程

完全体 1327

【LeetCode-数组】数组式整数加法

题目来源于 LeetCode 上第 989号(Add to Array-Form of Integer)问题,题目难度为 Easy,AC率44.6% 题目地址:https://leetcode.com/problems/add-to-array-form-of-integer/ 题目描述 For a non-negative integer X, the array-form of X is an...

weixin_34128501的博客 193

Java - 基本类的使用(集合类)

6.22笔记 集合类(可以理解为存储对象可变数组)树状图展示: Collection和Collections的区别 Collection是一个集合类的顶级接口,直接继承的接口有List和Set; Collections是一个操作集合的工具类,有多种方法对集合作一些操作; List(有顺序,可以重复添加)的基本使用: ArrayList(效率高,开发中使用最多) ArrayL

seaso52的博客 353

第13章 TreeMap、TreeSet、SkipList 与有序数据结构

空间换时间hash定位Key查询。

weixin_40653578的博客 222

Java程序设计语言

Java基础知识 1:数据类型 基本数据类型——内置数据类型 byte(8位):-128-127 short(16位):-32768-32767 int(32位) long(64位) float(32位) double(64位) boolean(默认值是false) char(16位Unicode字符)——Unicode字符:是一种重要的交互和显示的通用字符编码标准,可以适用于所有已知的编码。 内置数据类型互相比较时,比较的时它们的值。 非基本数据类型——复合数据类型 String Integer Date

weixin_45480995的博客 326

Java面向对象编程实战:Person-Student-Employee-Company类体系构建与核心概念解析

面向对象编程(OOP)是Java等现代编程语言的基石,其核心思想是通过类与对象来模拟现实世界,提升代码的复用性、可维护性和扩展性。其基本原理包括封装、继承和多态三大特性,其中继承允许子类获取父类的属性和方法,是实现代码复用的关键机制。这一技术价值在于能够构建层次清晰、易于管理的复杂系统,广泛应用于企业级应用、框架设计和业务建模等场景。本文以经典的“Person-Student-Employee-Company”类体系练习为例,深入剖析**构造器链**的调用顺序与**方法覆盖**的规范实现,通过具体代码演示如

weixin_34195142的博客 434

购物车(list)

product_list=[#建列表 ('Iphone',5800), ('MacPro',9800), ('Bike',800), ('Watch',10600), ('Coffee',31), ('Alex python',120), ] shopping_list=[]#购物车列表为空 salary=input("Input your sal...

weixin_42793797的博客 433
上一篇: 菜鸟程序员,被无良HR欺骗,因祸得福,竟“意外”拿下【得物】offer
下一篇: Github标星86k 的Spring Cloud学习教程+实战项目推荐!!上岸蚂蚁金服!!
Python_cola
博客等级 码龄5年 2031粉丝 74原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值