动态数组:ArrayList的实现原理

动态数组:ArrayList的实现原理

大家好!今天我们来聊聊Java集合框架中一个非常重要的数据结构——ArrayList。就像我们日常生活中使用的伸缩收纳盒一样,ArrayList可以根据需要自动调整大小,既方便又高效。那么它是如何实现这种"动态"特性的呢?让我们一起来探索它的实现原理。

在实际工作中,我们经常会遇到需要存储和处理大量数据的情况。ArrayList作为最常用的集合类之一,几乎每个Java开发者都会用到它。但是,仅仅知道如何使用是不够的,了解它的内部实现原理,才能让我们在开发中做出更合理的选择,避免潜在的性能问题。

一、ArrayList的基本概念

ArrayList是Java集合框架中的一个类,它实现了List接口,底层基于数组实现。与普通数组不同,ArrayList具有动态扩容的能力,可以根据需要自动调整容量。

以上图表展示了ArrayList的主要特点:基于数组实现、自动扩容、随机访问快但插入删除相对较慢。

1.1 ArrayList的核心字段

我们先来看看ArrayList类中的几个核心字段:

// 默认初始容量
private static final int DEFAULT_CAPACITY = 10;// 存储元素的数组
transient Object[] elementData;// ArrayList中实际存储的元素数量
private int size;

上述代码展示了ArrayList的三个核心字段:默认初始容量为10,elementData是实际存储元素的数组,size记录当前元素数量。

二、ArrayList的执行流程

理解了ArrayList的基本概念后,我们来看它的核心执行流程。ArrayList的操作主要围绕"增删改查"展开,其中最关键的是添加元素时的扩容机制。

以上流程图展示了ArrayList添加元素时的基本流程,其中扩容是关键步骤。

2.1 添加元素流程详解

让我们通过一个具体的例子来看看ArrayList添加元素的过程:

List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");

这段代码创建了一个ArrayList并添加了三个元素。在内部,ArrayList会经历初始化、添加元素、可能的扩容等过程。

三、ArrayList的技术原理

了解了执行流程后,我们深入探讨ArrayList的技术原理。ArrayList的核心在于它的动态扩容机制和数组操作。

3.1 初始化过程

当我们创建一个ArrayList时,会发生什么呢?

public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

这段代码展示了ArrayList的无参构造方法。实际上,在Java 8之后,ArrayList采用了延迟初始化的策略,只有在第一次添加元素时才会真正分配数组空间。

这个序列图展示了ArrayList从创建到添加元素的完整过程,特别是延迟初始化的特性。

3.2 扩容机制

扩容是ArrayList最核心的特性之一。让我们看看它是如何工作的:

private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);
}

这段代码展示了ArrayList的扩容方法。它首先计算新容量(通常是原来的1.5倍),然后检查边界条件,最后使用Arrays.copyOf创建新数组并复制元素。

考虑到性能和内存使用的平衡,ArrayList采用了1.5倍的扩容策略。这种策略既避免了频繁扩容带来的性能开销,又不会造成过多的内存浪费。

这个甘特图展示了ArrayList容量随着元素增加而增长的过程,每次扩容大约为原来的1.5倍。

3.3 元素访问

ArrayList的随机访问非常高效,因为它直接基于数组实现:

public E get(int index) {rangeCheck(index);return elementData(index);
}

这段代码展示了ArrayList的get方法实现。它首先检查索引是否合法,然后直接从数组中返回对应位置的元素,时间复杂度是O(1)。

3.4 元素删除

ArrayList的删除操作相对较慢,因为它需要移动元素:

public E remove(int index) {rangeCheck(index);E oldValue = elementData(index);int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index, numMoved);elementData[--size] = null; // 清除引用,帮助GCreturn oldValue;
}

这段代码展示了ArrayList的remove方法。删除元素后,它需要将后面的元素向前移动,这导致了O(n)的时间复杂度。

这个状态图展示了ArrayList的生命周期状态变化,从空数组到已初始化,再到可能的扩容状态。

四、ArrayList的性能分析

4.1 时间复杂度分析

ArrayList常见操作的时间复杂度:

  • get(int index): O(1) - 直接数组访问
  • add(E element): 平均O(1),最坏O(n)(需要扩容时)
  • add(int index, E element): O(n) - 需要移动元素
  • remove(int index): O(n) - 需要移动元素
  • contains(Object o): O(n) - 需要遍历查找

五、ArrayList的使用建议

基于ArrayList的实现原理和性能特点,我给大家一些使用建议:

这个思维导图总结了ArrayList的使用建议,包括初始化容量、批量操作、遍历选择和线程安全等方面。

5.1 初始化容量优化

如果你能预估元素数量,最好在创建ArrayList时指定初始容量:

// 不好的做法:可能导致多次扩容
List<String> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {list.add("item" + i);
}// 好的做法:预先设置容量
List<String> list = new ArrayList<>(10000);
for (int i = 0; i < 10000; i++) {list.add("item" + i);
}

这段代码对比了两种初始化ArrayList的方式。预先设置容量可以避免中间多次扩容,提高性能。

5.2 批量操作优化

当需要添加多个元素时,使用addAll比循环add更高效:

// 低效的做法
for (String item : anotherCollection) {list.add(item);
}// 高效的做法
list.addAll(anotherCollection);

这段代码展示了批量添加元素的两种方式。addAll方法通常只需要一次扩容,而循环add可能导致多次扩容。

六、总结

通过今天的讨论,我们深入了解了ArrayList的实现原理和使用技巧。让我们总结一下本文的主要内容:

  1. 基本概念:ArrayList是基于数组实现的动态数组,支持自动扩容
  2. 核心字段:elementData数组、size计数器、默认容量
  3. 执行流程:延迟初始化、扩容机制、元素操作
  4. 技术原理:1.5倍扩容策略、数组拷贝、元素移动
  5. 性能分析:随机访问快,插入删除可能较慢
  6. 使用建议:合理初始化容量、使用批量操作、注意线程安全

ArrayList作为Java集合框架中最常用的类之一,理解它的实现原理对我们编写高效代码非常重要。希望大家通过本文的学习,能够在实际工作中更加得心应手地使用ArrayList。

如果你有任何问题或想法,欢迎随时交流讨论。让我们一起进步,探索更多Java集合框架的奥秘!

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

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

相关文章

MIPI DSI(五) DBI 和 DPI 格式

关于 DBI 和 DPI 这两种格式的详细协议内容&#xff0c;请参考《MIPI Alliance Standard for Display Bus Interface&#xff08;V2.0&#xff09; .pdf》和《MIPI Alliance Standard for Display Pixel Interface&#xff08;DPI- 2&#xff09; .pdf》这两份文档。首先先了解…

FRP Ubuntu 服务端 + MacOS 客户端配置

一、服务端配置 1、下载frp并解压 # 创建目录并进入 mkdir -p /opt/frp && cd /opt/frp # 下载最新版&#xff08;替换URL为GitHub发布页最新版本&#xff09; wget https://github.com/fatedier/frp/releases/download/v0.59.0/frp_0.59.0_linux_amd64.tar.gz # 解压 …

Video Python(Pyav)解码二

在 PyAV 中&#xff0c;input_container.decode() 和 input_container.demux() 是两种处理视频流数据的不同方法&#xff0c;它们分别适用于不同的场景。下面通过代码示例和对比来详细说明它们的用法和区别。1. input_container.decode()功能直接解码&#xff1a;从容器中读取数…

闲庭信步使用图像验证平台加速FPGA的开发:第十六课——图像五行缓存的FPGA实现

&#xff08;本系列只需要modelsim即可完成数字图像的处理&#xff0c;每个工程都搭建了全自动化的仿真环境&#xff0c;只需要双击top_tb.bat文件就可以完成整个的仿真&#xff0c;大大降低了初学者的门槛&#xff01;&#xff01;&#xff01;&#xff01;如需要该系列的工程…

头文件与源文件及区别

使用场景上的区别头文件&#xff1a;变量的声明&#xff0c;函数的声明&#xff0c;宏的定义&#xff0c;类的定义等。 源文件&#xff1a;变量的定义。函数的定义实现&#xff0c;类成员函数的定义实现等。这样方便于我们去管理、规划&#xff0c;更重要的是避免了重定义的问题…

图机器学习(4)——图机器学习与嵌入算法

图机器学习&#xff08;4&#xff09;——图机器学习与嵌入算法0. 前言1. 图机器学习1.1 机器学习基本原理1.2 图机器学习的独特优势2. 广义图嵌入问题3. 图嵌入算法分类小结0. 前言 机器学习是人工智能的一个重要分支&#xff0c;它致力于让系统能够从数据中自主学习并持续优…

网络基础10--ACL与包过滤

一、ACL 定义与核心功能ACL&#xff08;访问控制列表&#xff09;是通过规则匹配实现数据包过滤或分类的核心技术&#xff0c;广泛应用于包过滤、NAT、QoS、路由策略等场景。其核心由规则条目组成&#xff0c;每条规则包含匹配条件&#xff08;如源 / 目 IP、端口、协议&#x…

Web安全 - 基于 SM2/SM4 的前后端国产加解密方案详解

文章目录概述一、背景与法规要求二、算法选型三、核心流程四、前端实现要点&#xff08;伪代码&#xff09;五、后端实现要点(伪代码)六、公钥存储策略七、全流程示例图八、总结与最佳实践推荐概述 随着信息安全法规日益严格&#xff0c;如《网络安全法》《数据安全法》和等保…

ACL动态路由实验全攻略:配置与安全实战

实验拓扑图 实验需求 步骤1.按照图示配置IP地址2.按照图示区域划分配置对应的动态路由协议3.在R7上配置dhcp服务器&#xff0c;能够让pc可以获取IP地址4.将所有环回宣告进ospf中&#xff0c;将环回17宣告进rip中&#xff0c;将rip路由引rospf中&#xff0c;ospf路由引.rip中5.要…

电动汽车制动系统及其工作原理

制动系统是实现车辆减速、停车功能的重要系统。电动汽车的制动系统按照制动实现方式分为机械制动和电机再生制动&#xff0c;机械制动根据制动力实现方式不同又可分为液压机械制动系统、气压机械制动系统和电子机械制动系统。目前&#xff0c;电动汽车的制动系统实现一般为协调…

CentOS 7 Linux 离线安装 docker-compose

CentOS 7 Linux 离线安装 docker-compose 1. docker-compose 简介 1.1. docker-compose 是什么&#xff1f; docker-compose 是 Docker 官方提供的工具&#xff0c;用于定义和运行多容器 Docker 应用程序。通过一个 YAML 文件&#xff08;通常为 docker-compose.yml&#xf…

排序算法实战(上)

一、引言在力扣刷题的旅程中&#xff0c;排序类题目是绕不开的重要板块。今天就来分享两道经典排序题——912. 排序数组和75. 颜色分类的解题思路与代码实现&#xff0c;带你深入理解排序算法在实际题目中的应用 。二、题目剖析与解题思路&#xff08;一&#xff09;912. 排序数…

python学智能算法(二十)|SVM基础概念-感知机算法及代码

引言 前序学习进程中&#xff0c;已经学习了超平面的基础知识&#xff0c;学习链接为&#xff1a;超平面 在此基础上&#xff0c;要想正确绘制超平面&#xff0c;还需要了解感知机的相关概念。 感知机 感知机是对生物神经网络的模拟&#xff0c;当输入信号达到感知机的阈值时…

操作HTML网页

一、HTML网页的介绍 HTML&#xff0c;即超文本标记语言&#xff08;HyperText Markup Language&#xff09;&#xff0c;它不是一种编程语言&#xff0c;而是一种标记语言&#xff0c;用于描述网页的结构。HTML 通过一系列标签来定义网页中的各种元素&#xff0c;如文本、图片…

Django--03视图和模板

Django–03视图和模板 Part 3: Views and templates 本教程承接第二部分&#xff0c;我们将继续开发投票应用&#xff0c;重点介绍 Django 的表单处理和通用视图。 文章目录Django--03视图和模板前言概述一、编写更多视图二、编写实际执行操作的视图三、快捷方式&#xff1a;r…

《每日AI-人工智能-编程日报》--2025年7月15日

介绍&#xff1a;AI &#xff1a;英伟达恢复向中国销售 H20 并推出新 GPU&#xff1a;7 月 15 日&#xff0c;英伟达官宣将恢复向中国销售 H20&#xff0c;并推出全新的 NVIDIA RTX PRO GPU&#xff0c;其中 B30 性能约为 H20 的 75%&#xff0c;定价在 6500 至 8000 美元之间&…

C++STL-list

一.基础概念相当于数据结构里面的双向链表二.基础操作1.list对象创建1. 默认构造函数list<int> l1;2. 初始化列表list<int> l2_1 { 9,8,7,6,5 };list<int> l2_2({ 9, 8, 7, 1, 5 });3. 迭代器list <int> l3(l2_1.begin(), l2_1.end());4. 全0初始化li…

【PTA数据结构 | C语言版】字符串插入操作

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 请编写程序&#xff0c;将给定字符串 t 插入到另一个给定字符串 s 的第 pos 个字符的位置。 输入格式&#xff1a; 输入先后给出主串 s 和待插入的字符串 t&#xff0c;每个非空字符串占一行&#…

Postman + Newman + Jenkins 接口自动化测试

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 </

CAS单点登录架构详解

目录 概述核心概念 TGC (Ticket Granting Cookie)TGT (Ticket Granting Ticket)ST (Service Ticket) 架构设计 整体架构存储架构安全机制 工作流程 完整登录时序流程步骤详解 技术实现 会话管理数据同步问题最佳实践 参考资料 概述 CAS (Central Authentication Service) 是…