深入源码解析ArrayList:探秘Java动态数组的机制与性能

文章目录

    • 一、 简介ArrayList
      • 1.1 介绍ArrayList的基本概念和作用
      • 1.2 与数组的区别和优势
    • 二、 内部实现
      • 2.1 数据结构:动态数组
      • 2.2 添加元素:add()方法的实现原理
      • 2.3 扩容机制:ensureCapacity()方法的实现原理
    • 三、 常见操作分析
      • 3.1 获取元素:get()方法的实现原理
      • 3.2 删除元素:remove()方法的实现原理
      • 3.3 修改元素:set()方法的实现原理
    • 四、 性能分析
      • 4.1 时间复杂度分析
      • 4.2 空间复杂度分析
      • 4.3 与LinkedList的比较
    • 五、 源码解读
      • 5.1 成员变量
      • 5.2 构造方法
      • 5.3 trimToSize()方法
      • 5.4 indexOf()方法
      • 5.5 clone()方法
      • 5.6 get()方法
      • 5.7 set()方法
      • 5.8 add()方法
      • 5.9 remove()方法
      • 5.10 addAll()方法
    • 六、 案例分析与实例演示
      • 6.1 案例分析
      • 6.2 实例演示

一、 简介ArrayList

1.1 介绍ArrayList的基本概念和作用

在Java中,ArrayList是一个实现了List接口的动态数组。它可以根据需要自动增加大小,因此可以存储任意数量的元素。

  1. 基本概念:
    • ArrayList是Java中常用的集合类之一,它可以存储对象,并且可以根据索引访问和操作这些对象。
    • ArrayList是基于数组实现的,但是它具有动态扩展的能力,因此可以动态地增加和减少元素的数量。
  2. 作用:
    • 存储数据:ArrayList可以用来存储各种类型的数据,包括基本类型和对象类型。
    • 动态扩展:由于ArrayList的大小是动态的,因此它非常适合需要动态增加和减少元素的场景。
    • 方便操作:ArrayList提供了丰富的方法来操作元素,比如添加、删除、查找等,使得对集合的操作变得非常便利。

总之,ArrayList在Java中是非常常用的数据结构,它提供了动态存储数据的能力,以及丰富的操作方法,非常适合在开发中使用。

1.2 与数组的区别和优势

ArrayList是一种动态数组,它是基于数组实现的,但具有动态扩展和收缩的能力。与普通数组相比,ArrayList具有以下区别和优势:

  1. 大小动态性:ArrayList的大小是动态的,可以根据需要动态扩展和收缩。而普通数组的大小是固定的,一旦创建就无法改变。
  2. 自动扩展:当ArrayList中的元素数量超过当前容量时,ArrayList会自动进行扩展,而普通数组需要手动重新分配内存并复制数据。
  3. 插入和删除元素效率高:ArrayList支持在任意位置插入和删除元素,而普通数组在插入和删除元素时需要移动其他元素。
  4. 内置方法和功能:ArrayList提供了许多便捷的方法和功能,如添加、删除、查找等操作,使其更易于使用和操作。

总的来说,ArrayList相对于普通数组来说更加灵活、便捷,并且具有更高的操作效率。因此,在大多数情况下,使用ArrayList比使用普通数组更加方便和实用。

二、 内部实现

2.1 数据结构:动态数组

在Java中,ArrayList是一个动态数组实现的类,它是基于数组实现的动态数组,可以自动扩容。下面是ArrayList的动态数组原理:

  1. 内部数组:ArrayList内部使用一个数组来存储元素。当创建一个ArrayList时,会初始化一个初始容量的数组。
  2. 自动扩容:当向ArrayList中添加元素时,如果当前数组已满,ArrayList会创建一个新的更大容量的数组,并将原数组中的元素复制到新数组中,然后将新元素添加到新数组中。
  3. 扩容策略:ArrayList的扩容策略是在每次扩容时将当前容量扩大为原来的1.5倍,这种策略既能够保证空间利用率,又能够减少因频繁扩容而带来的性能开销。
  4. 随机访问:由于ArrayList内部基于数组实现,因此支持随机访问,可以通过索引直接访问数组中的元素,时间复杂度为O(1)

总的来说,ArrayList通过动态扩容的方式,利用数组实现了一个动态数组,提供了高效的随机访问和动态增删元素的功能。

2.2 添加元素:add()方法的实现原理

在Java中,ArrayList的add()方法用于向ArrayList中添加元素。

其实现原理如下:

  1. 在调用add()方法时,先检查当前ArrayList的大小和容量(即存储空间是否足够)。
  2. 如果当前容量不够,就进行扩容操作。一般情况下,会创建一个新的数组,将原数组中的元素复制到新数组中,并且为新数组分配更大的存储空间。
  3. 然后将要添加的元素放入ArrayList的内部数组中,并更新ArrayList的大小。
  4. 如果添加成功,则返回true,如果添加失败,则返回false

总的来说,ArrayList的add()方法实现原理就是对内部数组的扩容和元素的添加操作。

2.3 扩容机制:ensureCapacity()方法的实现原理

在使用ArrayList时,如果我们预先知道将要插入的元素数量,可以使用ensureCapacity()方法来预先分配内部数组大小。调用了一个名为ensureCapacityInternal()的私有方法。这个方法首先会判断当前内部数组是否已经足够大来容纳新增的元素,如果不够大,则会进行扩容:

  1. 如果当前内部数组为空,则直接扩容到指定容量大小。
  2. 否则,计算出新数组的容量大小,这个容量大小取决于原始数组的大小和扩容因子(默认为1.5倍)。
  3. 如果新数组容量大小小于所需容量,则按照所需容量分配新的数组;否则,按照新数组容量大小分配新的数组。
  4. 将原始数组中的元素复制到新数组中,并将新数组赋值给ArrayList对象的elementData变量。
import java.util.ArrayList;public class EnsureCapacityExample {public static void main(String[] args) {// 创建一个空的ArrayListArrayList<String> list = new ArrayList<>();// 预先设定ArrayList内部数组的容量为20list.ensureCapacity(20);// 现在,ArrayList的内部数组至少可以容纳20个元素// 添加元素到ArrayListlist.add("Element 1");list.add("Element 2");list.add("Element 3");// ...}
}

通过使用ensureCapacity()方法,我们可以避免由于频繁扩容带来的性能损失,提高程序效率。

三、 常见操作分析

3.1 获取元素:get()方法的实现原理

在Java中,ArrayList的get()方法实际上是通过调用数组的索引来获取指定位置的元素。ArrayList内部维护了一个Object类型的数组来存储元素。

  • 当调用get()方法时,ArrayList会将传入的索引作为数组的下标,直接访问数组中对应位置的元素,并返回该元素。
  • 因为数组的访问是基于内存地址的,所以获取元素的时间复杂度为O(1),即常数时间复杂度。
  • ArrayList的get()方法并不会对数组进行拷贝或重新分配空间,因此在获取元素时是非常高效的。
  • 频繁进行插入、删除等涉及数组扩容的操作,可能会导致性能下降。

ArrayList的get()方法通过直接访问底层数组的方式快速获取指定位置的元素。

3.2 删除元素:remove()方法的实现原理

Java中的ArrayList类是基于数组实现的动态数组,当我们使用remove()方法从ArrayList中删除元素时,这个方法会将指定位置的元素从内部数组中移除,并将后续元素向前移动一位。

这个操作可以通过以下几个步骤来实现:

  1. 检查待删除的元素下标是否越界,如果越界则抛出IndexOutOfBoundsException异常。
  2. 将要删除的元素从内部数组中移除,这个过程可以通过System.arraycopy()方法来实现,该方法可以将数组的某一范围内的元素复制到另一个位置上。
  3. 将后续元素向前移动一位,以填补被删除的空位。这个过程同样可以通过System.arraycopy()方法来实现。

ps:ArrayList的remove()方法只能移除第一个与指定元素相等的元素。如果我们想要移除所有等于指定元素的元素,可以通过循环遍历ArrayList并使用remove()方法来实现。

3.3 修改元素:set()方法的实现原理

Java中的ArrayList是一种基于数组的动态数组实现,它继承了AbstractList类并实现了List接口。set()方法是ArrayList中的一个方法,用于将指定索引位置的元素替换为新的元素。

其实现原理如下

  1. 首先,set()方法会检查传递的索引是否在ArrayList范围之内。如果索引小于0或大于等于ArrayList的大小(size()方法返回的值),则会抛出IndexOutOfBoundsException异常。
  2. 如果索引有效,则会使用数组的索引定位到指定的元素,并将其替换为新的元素。
  3. set()方法返回被替换掉的元素。
  4. 在替换元素时,ArrayList可能需要调整内部数组的大小。如果新元素的大小与当前数组的容量不匹配,ArrayList会创建一个新数组,并将所有元素从旧数组复制到新数组中。

总之,ArrayList的set()方法的实现原理是通过数组索引定位和替换元素来完成的,而且可能需要动态调整内部数组的大小。

四、 性能分析

4.1 时间复杂度分析

在Java中,ArrayList是一个动态数组实现的集合类,它提供了随机访问和快速插入/删除元素的功能。

下面是ArrayList的常见操作及其时间复杂度分析

  1. 访问元素(get):通过索引访问特定位置的元素,时间复杂度为O(1)
  2. 插入元素(add):在指定位置插入元素,平均时间复杂度为O(n),最坏情况下需要将插入位置之后的元素都向后移动,时间复杂度为O(n)
  3. 删除元素(remove):删除指定位置的元素,平均时间复杂度为O(n),最坏情况下需要将删除位置之后的元素都向前移动,时间复杂度为O(n)
  4. 查找元素(contains):判断集合中是否包含某个元素,平均时间复杂度为O(n),需要遍历整个集合来查找。
  5. 获取集合大小(size):获取集合中元素的数量,时间复杂度为O(1)

需要注意的是,ArrayList的插入和删除操作涉及到元素的移动,当集合的大小较大时,这些操作可能会导致性能下降。如果需要频繁进行插入和删除操作,可以考虑使用LinkedList来代替ArrayList,因为LinkedList对于插入和删除操作的时间复杂度是O(1)

4.2 空间复杂度分析

ArrayList的空间复杂度主要取决于两个因素:集合中的元素数量和内部数组的容量。

  1. 元素数量:ArrayList存储的元素数量,即集合的大小,会占用一定的空间。假设元素数量为n,则空间复杂度为O(n)
  2. 内部数组容量:ArrayList内部使用一个动态数组来存储元素,数组的容量可能会比集合的大小大一些,以容纳未来添加的元素。假设数组的容量为m,则空间复杂度为O(m)

需要注意的是,ArrayList的实际空间占用可能会比集合中的元素数量多一些,因为它预留了一些额外的容量供后续添加元素使用。当集合的元素数量接近或超过内部数组的容量时,ArrayList会自动进行扩容操作,重新分配更大的数组并将原有元素复制到新数组中,这可能会导致空间复杂度的增加。

在实际使用中,可以通过调整ArrayList的初始容量或使用构造函数指定初始容量来控制空间复杂度。通常情况下,如果能够预估集合的大小,设置一个适当的初始容量可以减少扩容操作的频率,提高性能。

4.3 与LinkedList的比较

ArrayList和LinkedList是Java中两种常见的集合类,它们都实现了List接口,但在内部实现和性能特点上有所不同。

下面是ArrayList和LinkedList的比较

  1. 内部实现
    • ArrayList:使用动态数组实现,内部维护一个可变长度的数组来存储元素。
    • LinkedList:使用双向链表实现,内部由一系列节点组成,每个节点包含元素值和前后指针。
  2. 访问效率
    • ArrayList:由于使用数组实现,可以通过索引直接访问元素,因此随机访问的效率很高,时间复杂度为O(1)。但在插入和删除元素时,需要移动数组中的元素,效率较低,时间复杂度为O(n)
    • LinkedList:插入和删除元素的效率较高,因为只需要调整节点的指针,时间复杂度为O(1)。但在随机访问元素时,需要从头节点开始按序遍历查找,效率较低,时间复杂度为O(n)
  3. 空间占用
    • ArrayList:使用动态数组,会预留一定容量的空间,当元素数量超过容量时,需要进行扩容操作。因此,可能会有额外的空间浪费。
    • LinkedList:使用链表结构,每个节点除了存储元素还需要存储前后节点的指针,因此会略微增加一些额外空间。
  4. 适用场景:
    • ArrayList:适合于随机访问和遍历操作较多的场景,例如根据索引访问元素、遍历集合等。但在频繁插入和删除元素的情况下,性能相对较差。
    • LinkedList:适合于频繁插入和删除元素的场景,例如实现队列或栈等数据结构。但在随机访问元素时,性能相对较差。

五、 源码解读

5.1 成员变量

在这里插入图片描述

5.2 构造方法

在这里插入图片描述

5.3 trimToSize()方法

在这里插入图片描述

5.4 indexOf()方法

在这里插入图片描述

5.5 clone()方法

在这里插入图片描述

5.6 get()方法

在这里插入图片描述

5.7 set()方法

在这里插入图片描述

5.8 add()方法

在这里插入图片描述

5.9 remove()方法

在这里插入图片描述

5.10 addAll()方法

在这里插入图片描述

六、 案例分析与实例演示

6.1 案例分析

假设有一个学生管理系统,需要存储学生的信息,包括姓名、年龄、性别等。

为了方便管理,我们可以使用ArrayList来存储学生对象。

首先定义一个学生类,包含姓名、年龄、性别三个属性

public class Student {private String name;private int age;private String gender;public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}// getter 和 setter 方法省略
}

然后在主类中创建ArrayList对象,并添加学生信息

import java.util.ArrayList;public class Main {public static void main(String[] args) {// 创建ArrayList对象ArrayList<Student> list = new ArrayList<>();// 添加学生信息list.add(new Student("张三", 18, "男"));list.add(new Student("李四", 20, "女"));list.add(new Student("王五", 19, "男"));// 遍历学生信息for (Student student : list) {System.out.println("姓名:" + student.getName() + " 年龄:" + student.getAge() + " 性别:" + student.getGender());}}
}

输出结果如下

姓名:张三 年龄:18 性别:男
姓名:李四 年龄:20 性别:女
姓名:王五 年龄:19 性别:男

6.2 实例演示

演示一下如何使用ArrayList实现一个简单的购物车程序。

首先定义一个商品类,包含名称和价格两个属性

public class Product {private String name;private double price;public Product(String name, double price) {this.name = name;this.price = price;}// getter 和 setter 方法省略
}

然后在主类中创建ArrayList对象,并添加商品信息

import java.util.ArrayList;
import java.util.Scanner;public class ShoppingCart {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 创建ArrayList对象ArrayList<Product> cart = new ArrayList<>();// 添加商品信息cart.add(new Product("可乐", 3.5));cart.add(new Product("薯片", 5.0));cart.add(new Product("巧克力", 8.0));// 输出商品信息System.out.println("欢迎来到购物车!");for (Product product : cart) {System.out.println(product.getName() + " 价格:" + product.getPrice());}// 计算总价double totalPrice = 0;while (true) {System.out.print("请输入要购买的商品编号(输入-1结束):");int index = scanner.nextInt();if (index == -1) {break;}Product product = cart.get(index);System.out.println("已选择 " + product.getName() + " 价格:" + product.getPrice());totalPrice += product.getPrice();}System.out.println("总价:" + totalPrice);}
}

运行程序,输出结果如下

欢迎来到购物车!
可乐 价格:3.5
薯片 价格:5.0
巧克力 价格:8.0
请输入要购买的商品编号(输入-1结束):0
已选择 可乐 价格:3.5
请输入要购买的商品编号(输入-1结束):1
已选择 薯片 价格:5.0
请输入要购买的商品编号(输入-1结束):2
已选择 巧克力 价格:8.0
请输入要购买的商品编号(输入-1结束):-1
总价:16.5

盈若安好,便是晴天

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

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

相关文章

0基础学习VR全景平台篇第127篇:什么是VR全景/720全景漫游?

“全景”作为一种表现宽阔视野的手法&#xff0c;在很久之前就得到了普遍的认同。北宋年间&#xff0c;由张择端绘制的《清明上河图》就是一幅著名的全景画。摄影术出现后&#xff0c;全景摄影也随之而生。 到今天&#xff0c;全景拍摄不再被专业摄影师所独享&#xff0c;广大…

C#的线程技术及操作(Thread类)

目录 一、线程基础 1.单线程 2.多线程 &#xff08;1&#xff09;多线程的缺点 &#xff08;2&#xff09;多线程的缺点 二、线程操作之Thread类 1. Thread类的相关方法和属性 &#xff08;1&#xff09;示例源码 &#xff08;2&#xff09;生成效果 2.创建线程Star…

代码随想录算法训练营 | day50 动态规划 123.买卖股票的最佳时机Ⅲ,188.买卖股票的最佳时机Ⅳ

刷题 123.买卖股票的最佳时机Ⅲ 题目链接 | 文章讲解 | 视频讲解 题目&#xff1a;给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&#xff1a;你不能同时参与多笔…

获取CAD图元名及图元信息(circle为例,用于选择集,对应dxf组码)

在CAD编程中往往需要用选择集&#xff0c;我们往往不知道相应图元对应的名称具体名字。比如我想选择所有的圆&#xff0c;ftype0,fdata应该是什么呢&#xff1f;是circle&#xff0c;acdbcircle&#xff0c;还是acadcircle? circle是一个对象&#xff0c;circle的vba类名为Ac…

SAP 散装物料简介

散装物料(Bulk Material),也叫做间接物料(Indirect Material),是一般企业在库存管理时常见的一种物料形式。散装物料专指那些价值小、消耗量大、消耗率高的物料件。这些物料组件同样服务于企业的生产活动,并且在企业的工作中心中被生产活动直接消耗(如螺丝钉、润滑油、…

海底数据中心:数据存储未来发展的新方向

随着信息技术的快速发展&#xff0c;数据需求量呈指数级增长&#xff0c;数据中心作为数据处理和存储的重要基础设施&#xff0c;其地位和作用愈发凸显。然而&#xff0c;传统的数据中心由于能耗大、碳排放高、土地占用等问题&#xff0c;已经难以满足可持续发展的需求。在此背…

Swin UNetR:把 UNet 和 Swin Transformer 结合

Swin UNetR&#xff1a;把 UNet 和 Swin Transformer 结合 网络结构使用指南 前置知识&#xff1a;Swin Transformer&#xff1a;将卷积网络和 Transformer 结合 Swin UNetR 结合 Swin Transformer 的上下文建模能力和 U-Net 的像素级别预测能力&#xff0c;提高语义分割任务的…

初始数据库 - 了解数据库

centos 7 版本当中安装 mysql 安装与卸载中&#xff0c;⽤⼾全部切换成为root&#xff0c;⼀旦 安装&#xff0c;普通⽤⼾是可以使用的。 卸载不需要的环境 首先&#xff0c;在安装之前&#xff0c;要先确定你当前系统当中是否已经有了mysql 的环境&#xff0c;如果你不想卸…

maui下sqlite演示增删改查

数据操作类 有分页 todoitemDatabase.cs&#xff1a; using SQLite; using TodoSQLite.Models;namespace TodoSQLite.Data {public class TodoItemDatabase{SQLiteAsyncConnection Database;public TodoItemDatabase(){}// 初始化数据库连接和表async Task Init(){if (Databa…

积雪深度智能化监测JL-29 雪深监测仪

积雪深度智能化监测JL-29 雪深监测仪产品简介 该设备通过安装于固定高度的可视激光探测传感器采用相位差式测量方法对雪深数据连续在线监测。同时&#xff0c;根据长期使用情况需要&#xff0c;提供连续准确的数据支持。可在无人值守的恶劣环境下全自动正常运行&#xff0c;并…

PPT插件-好用的插件-字距快速设置-大珩助手

字距快速设置 包含两端对齐、段首缩进、取消缩进、字间距、行间距、段后距 段首缩进 每次缩进两个字符&#xff0c;可对选中的文字、选中的多个文本对象两个层级操作 取消缩进 将缩进取消&#xff0c;可对选中的文字、选中的多个文本对象两个层级操作 字间距 预设了常用…

【GlobalMapper精品教程】065:连接SQL Server空间数据库并加载数据

Global Mapper是一个地图创建和编辑工具,无法像ArcGIS一样,基于SQL Server等大型关系型数据库。它本身也并不直接连接数据库。但是,Global Mapper可以与其他软件集成,以从数据库中获取数据并在地图上显示。本文讲述Global Mapper连接SLQ Server数据库的方法。 一、创建数据…

深入理解 Goroutines 和 Go Scheduler

本文将重点帮助您了解 Golang 中的 goroutines。Go 调度程序如何工作以在 Go 中实现最佳并发性能。我会尽力用简单的语言解释,这样你就可以理解了。 我们将介绍什么是操作系统中的线程和进程,什么是并发,为什么实现并发很难,以及 goroutines 如何帮助我们实现并发。然后,…

AtCoder ABC周赛2023 12/10 (Sun) D题题解

目录 原题截图&#xff1a; 题目大意&#xff1a; 主要思路&#xff1a; 注&#xff1a; 代码&#xff1a; 原题截图&#xff1a; 题目大意&#xff1a; 给定两个 的矩阵 和 。 你每次可以交换矩阵 的相邻两行中的所有元素或是交换两列中的所有元素。 请问要使 变换至…

JVM虚拟机系统性学习-垃圾回收器Serial、ParNew、Parallel Scavenge和Parallel Old

垃圾回收器 有 8 种垃圾回收器&#xff0c;分别用于不同分代的垃圾回收&#xff1a; 新生代回收器&#xff1a;Serial、ParNew、Parallel Scavenge老年代回收器&#xff1a;Serial Old、Parallel Old、CMS整堆回收器&#xff1a;G1、ZGC Serial&#xff1a;串行回收 Serial是…

RT-DETR改进策略:双动态令牌混合器(D-Mixer)的TransXNet,实现RT-DETR的有效涨点

摘要 双动态令牌混合器(D-Mixer),一种输入依赖的方式聚合全局信息和局部细节。D-Mixer通过分别在均匀分割的特征片段上应用有效的全局注意力模块和输入依赖的深度卷积,使网络具有强大的归纳偏差和扩大的有效感受野。使用D-Mixer作为基本构建块设计了TransXNet,这是一种新…

Unity中实现ShaderToy卡通火(总结篇)

文章目录 前言一、把卡通火修改为后处理效果1、在Shader属性面板定义属性接收帧缓存纹理2、在片元着色器对其纹理采样后&#xff0c;与卡通火相加输出请添加图片描述 二、我们自定义卡通火1、修改 _CUTOFF 使卡通火显示在屏幕两侧2、使火附近屏幕偏红色 前言 在之前的文章中&a…

【IC验证】perl脚本——分析前/后仿用例回归情况

目录 1 脚本名称 2 脚本使用说明 3 nocare_list文件示例 4 脚本执行方法 5 postsim_result.log文件示例 6 脚本代码 1 脚本名称 post_analysis 2 脚本使用说明 help&#xff1a;打印脚本说明信息 命令&#xff1a;post_analysis help 前/后仿结束后&#xff0c;首先填…

计算机毕业设计 SpringBoot的企业内管信息化系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

首场“解数Talk” 直播来了——大模型语料数据联盟开源数据集解读

一、解数 Talk 介绍 为帮助广大开发者更好地了解大模型语料数据联盟发布的AI大模型语料数据&#xff0c;沟通大模型企业在AI视角下的数据需求&#xff0c;不断服务大模型产业生态和落地应用&#xff0c;联盟发起单位上海人工智能实验室联合成员单位共同打造“解数 Talk”系列直…