Java ArrayList 详解

Java ArrayList 详解

ArrayList 是 Java 集合框架(Collection Framework)中最常用的类之一,是一种基于动态数组的数据结构,属于 List 接口的实现类。它允许存储重复的元素,有序,支持随机访问,且动态扩容。


1. ArrayList 的特点

  1. 有序ArrayList 按照元素插入的顺序存储,并按索引位置访问。
  2. 允许重复元素:可以存储重复值。
  3. 动态扩容:当容量不足时,会自动扩展存储空间。
  4. 随机访问:通过索引快速访问元素(时间复杂度 O(1))。
  5. 线程不安全ArrayList 不是线程安全的,多个线程同时修改需要手动同步。
  6. 实现接口:实现了 List 接口,同时支持 RandomAccessCloneableSerializable

2. ArrayList 的基本用法

2.1 创建与初始化
import java.util.ArrayList;public class ArrayListExample {public static void main(String[] args) {// 创建空的 ArrayListArrayList<String> list = new ArrayList<>();// 添加元素list.add("Apple");list.add("Banana");list.add("Cherry");// 输出列表System.out.println("List: " + list); // 输出: [Apple, Banana, Cherry]}
}
2.2 常用方法
import java.util.ArrayList;public class ArrayListExample {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();// 添加元素list.add("A");list.add("B");list.add("C");// 获取元素System.out.println("Element at index 1: " + list.get(1)); // 输出: B// 修改元素list.set(1, "Z");System.out.println("After update: " + list); // 输出: [A, Z, C]// 删除元素list.remove("A");System.out.println("After removal: " + list); // 输出: [Z, C]// 检查是否包含System.out.println("Contains B? " + list.contains("B")); // 输出: false// 遍历for (String s : list) {System.out.println(s);}// 清空列表list.clear();System.out.println("Is empty? " + list.isEmpty()); // 输出: true}
}

3. ArrayList 的常用操作方法

方法描述
add(E e)在列表末尾添加元素。
add(int index, E element)在指定位置插入元素,原位置及后续元素右移。
remove(Object o)删除首次出现的指定元素。
remove(int index)删除指定索引位置的元素。
get(int index)获取指定索引位置的元素。
set(int index, E element)替换指定索引位置的元素为新的元素。
size()返回列表中元素的数量。
contains(Object o)检查列表中是否包含指定元素。
indexOf(Object o)返回元素的首次出现位置,若不存在则返回 -1。
lastIndexOf(Object o)返回元素最后一次出现的位置。
clear()清空列表中的所有元素。
isEmpty()检查列表是否为空。
toArray()将列表转换为数组。
addAll(Collection<? extends E>)添加另一个集合的所有元素到列表。
sort(Comparator<? super E>)对列表进行排序。

4. ArrayList 的工作原理

4.1 动态数组实现
  • 初始容量:创建时,如果未指定容量,ArrayList 默认初始容量为 10
  • 扩容机制:当存储的元素数量超过当前容量时,ArrayList 会动态扩容。扩容后的新容量为 原容量的 1.5 倍
  • 实现细节:底层通过数组 Object[] elementData 来存储元素。

扩容的实现代码:

private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量 = 原容量 + 原容量的一半if (newCapacity - minCapacity < 0)newCapacity = minCapacity;elementData = Arrays.copyOf(elementData, newCapacity);
}
4.2 随机访问
  • 通过数组的索引访问,效率高,时间复杂度为 O(1)
4.3 插入和删除
  • 插入或删除会导致后续元素的移动,时间复杂度为 O(n)

5. ArrayList 的优缺点

5.1 优点
  1. 随机访问效率高:支持通过索引快速访问元素。
  2. 动态扩容:容量不足时自动扩展,无需手动调整。
  3. 实现了丰富的操作方法:提供增删改查、排序等常用操作。
5.2 缺点
  1. 插入和删除效率低:需要移动后续元素,尤其是在中间位置操作时。
  2. 线程不安全:在多线程环境中需要额外同步机制。
  3. 扩容成本高:扩容时需要分配新数组并拷贝旧数组的元素。

6. 线程安全的替代方案

6.1 Vector
  • Vector 是线程安全的 ArrayList 替代方案,但由于每个方法都进行同步,性能较低。
6.2 Collections.synchronizedList
  • 可以通过 Collections.synchronizedList 包装一个线程安全的 ArrayList
import java.util.*;public class SynchronizedListExample {public static void main(String[] args) {List<String> list = Collections.synchronizedList(new ArrayList<>());list.add("A");list.add("B");synchronized (list) {for (String s : list) {System.out.println(s);}}}
}
6.3 CopyOnWriteArrayList
  • 在多线程环境中使用 CopyOnWriteArrayList,每次写操作都会创建新的副本,适用于读多写少的场景。

7. 常见问题与注意事项

  1. 越界异常

    • 尝试访问不存在的索引位置会抛出 IndexOutOfBoundsException
    list.get(10); // 若列表长度不足,抛异常
    
  2. 性能问题

    • 插入、删除操作在列表越靠后的位置,性能越高。
    • 遍历时,建议使用增强型 for 循环或迭代器。
  3. 多线程环境

    • ArrayList 是非线程安全的,多线程操作时需显式同步。

8. 总结

特性描述
实现结构动态数组,支持随机访问,扩容按 1.5 倍增长。
线程安全性非线程安全,需要显式同步或使用线程安全的替代方案。
性能读取效率高(O(1)),插入和删除效率低(O(n))。
适用场景适合需要频繁读取元素的场景,不适合高频插入或删除场景。

ArrayList 是 Java 中灵活且高效的动态数组实现,在开发中广泛应用于需要存储有序、可重复数据的场景。理解其特性和工作原理,合理使用它,能够显著提升程序的性能和可维护性。

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

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

相关文章

springboot/ssm线上教育培训办公系统Java代码web项目在线课程作业源码

springboot/ssm线上教育培训办公系统Java代码web项目在线课程作业源码 基于springboot(可改ssm)htmlvue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&…

Rust学习笔记_13——枚举

Rust学习笔记_10——守卫 Rust学习笔记_11——函数 Rust学习笔记_12——闭包 枚举 文章目录 枚举1. 定义1.1 无值变体1.2 有值变体1.3 枚举与泛型的结合 2. 使用2.1 和匹配模式一起使用2.2 枚举作为类型别名 3. 常用枚举类型 在Rust编程语言中&#xff0c;枚举&#xff08;enum…

容器运行应用及Docker命令

文章目录 一、使用容器运行Nginx应用1_使用docker run命令运行Nginx应用1 观察下载容器镜像过程2 观察容器运行情况 2_访问容器中运行的Nginx服务1 确认容器IP地址2 容器网络说明3 使用curl命令访问 二、Docker命令1_Docker命令获取帮助方法2_Docker官网提供的命令说明3_docker…

深入浅出:php-学习入门全攻略

文章目录 1. 为什么选择 PHP&#xff1f;2. 安装 PHP 环境2.1 Windows 系统安装步骤 1&#xff1a;下载 PHP步骤 2&#xff1a;解压并配置步骤 3&#xff1a;配置环境变量步骤 4&#xff1a;验证安装 2.2 Mac 系统安装步骤 1&#xff1a;使用 Homebrew 安装步骤 2&#xff1a;验…

【热门主题】000075 探索嵌入式硬件设计的奥秘

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

数据分析(一): 掌握STDF 掌握金钥匙-码农切入半导体的捷径

中国的半导体行业必然崛起&#xff01;看清这个大势&#xff0c;就会有很多机会。 今天&#xff0c;我们一起来了解一下半导体行业的一朵金花&#xff1a;STDF。 实际上这只是一种文件格式&#xff0c;但是当你熟练掌握解析这种文件的时候&#xff0c;你就已经打开在这个基础…

PostgreSQLt二进制安装-contos7

1、安装依赖 yum install -y gcc readline readline-devel zlib-devel net-tools perl wget numactl libicu-devel bison flex openssl-devel pam pam-devel libxml2 libxml2-devel libxslt libxslt-devel openldap openldap-devel 2、创建目录 mkdir -p /data/postgresql/{…

Latex转word(docx)或者说PDF转word 一个相对靠谱的方式

0. 前言 投文章过程中总会有各种各样的要求&#xff0c;其中提供word格式的手稿往往是令我头疼的一件事。尤其在多公式的文章中&#xff0c;其中公式转换是一个头疼的地方&#xff0c;还有很多图表&#xff0c;格式等等&#xff0c;想想就让人头疼欲裂。实践中摸索出一条相对靠…

AWS创建ec2实例并连接成功

aws创建ec2实例并连接 aws创建ec2并连接 1.ec2创建前准备 首先创建一个VPC隔离云资源并且有公有子网 2.创建EC2实例 1.启动新实例或者创建实例 2.创建实例名 3.选择AMI使用linux(HVM) 4.选择实例类型 5.创建密钥对下载到本地并填入密钥对名称 6.选择自己创建的VPC和公有子网…

“放弃Redis Desktop Manager使用Redis Insight”:日常使用教程(Redis可视化工具)

文章目录 更新Redis Insight连接页面基础解释自动更新key汉化暂时没有找到方法&#xff0c; Redis Desktop Manager在连接上右键在数据库上右键在key上右键1、添加连接2、key过期时间 参考文章 更新 (TωT)&#xff89;~~~ β&#xff59;ё β&#xff59;ё~ 现在在维护另一…

如何用注册机破解Reflexive游戏

相信有许多小朋友&#xff08;像我以前一样&#xff09;已经迫不及待地准备准备对浩瀚的、像三星堆一般的Reflexive游戏合集进行考古挖掘工作了。不巧的是&#xff0c;打开游戏之后发现常常提示要付费才能解锁完整版。 一、下载注册机与破解文件 首先&#xff0c;在我的永硕网…

Java 多线程探秘:从线程池到死锁的奇幻之旅

1.简述一下你对线程池的理解 线程池是一种多线程处理形式&#xff0c;处理过程中将任务分为若干个线程&#xff0c;使用线程池可以有效地管理并发线程的数量&#xff0c;提高程序的响应速度和资源利用率。以下是关于线程池的一些关键点&#xff1a; 预创建线程&#xff1a;线…

一万台服务器用saltstack还是ansible?

一万台服务器用saltstack还是ansible? 选择使用 SaltStack 还是 Ansible 来管理一万台服务器&#xff0c;取决于几个关键因素&#xff0c;如性能、扩展性、易用性、配置管理需求和团队的熟悉度。以下是两者的对比分析&#xff0c;帮助你做出决策&#xff1a; SaltStack&…

PDF文件页面转换成图片怎么弄-免费PDF编辑工具分享

>>更多PDF文件处理应用技巧请前往 96缔盟PDF处理器 主页 查阅&#xff01; —————————————————————————————————————— 序言 我之前的文章也有介绍过如何使用96缔盟PDF处理器对PDF文件转换成图片&#xff0c;但是当时是使用DMPDFU…

从 scratch开始构建一个最小化的 Hello World Docker 镜像-docker的镜像源头

在这篇文章中&#xff0c;我们将学习如何从零开始构建一个最小化的 Docker 镜像&#xff0c;基于 scratch 镜像&#xff0c;并在其中运行一个简单的 “Hello World” 程序。 Scratch 是一个空白的基础镜像&#xff0c;适用于构建轻量化、独立的容器。由于 scratch 不包含任何系…

OpenHarmony-4.GPIO驱动

GPIO 1.功能简介 GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出。GPIO又俗称为I/O口&#xff0c;I指的是输入(in&#xff09;&#xff0c;O指的是输出&#xff08;out&#xff09;。可以通过软件来控制其输入和输出&#xff0c;即I/O控制。通常&…

网络安全xss和csrf

xss和csrf介绍 1.xss 跨站脚本攻击&#xff0c;csrf 跨站请求伪造 2.xss 浏览器向服务器请求时注入脚本攻击 分为三种类型&#xff1a;反射性&#xff08;非持久型&#xff09;、存储型&#xff08;持久型&#xff09;、基于dom 防范手段&#xff1a;输入过滤、输出过滤、加ht…

1、操控UART寄存器实现输出功能

在这一章里&#xff0c;重点需要了解如何通过寄存器操控GPIO、UART&#xff0c;使得MCU通过UART总线输出字符&#xff0c;实现打印功能。 一、GPIO相关寄存器 如果开发板上引脚资源够用的话&#xff0c;并不需要额外配置GPIO的复用功能。但如果想要复用GPIO为某一路UART的功能…

leetcode 1843 可疑银行账户(postgresql)

需求 表: Accounts -------------------- | Column Name | Type | -------------------- | account_id | int | | max_income | int | -------------------- account_id 是表主键。 每行包含一个银行账户每月最大收入的信息。 表: Transactions ------------------------ |…

【开源代码】图像水印移除-依赖python-tensorflow

下载源码 git clone https://github.com/zuruoke/watermark-removal创建conda环境 conda create -n tensorflow_gpu python=3.7 conda activate tensorflow_gpu conda install tensorflow-gpu==1.15