当前位置: 首页 > java >正文

数据结构-ArrayList

在 Java 集合框架中,ArrayList 是 List 接口最常用的实现类之一,因其查询效率高、使用灵活的特点,广泛应用于日常开发。本文将从 ArrayList 的核心特点、常用方法、遍历方式到使用注意事项,进行系统性梳理,帮助快速复习并掌握其核心用法。

一、ArrayList 核心特点

ArrayList 本质是动态数组(底层基于数组实现),相比普通数组,它能自动扩容以存储更多元素,同时保留了数组 “按索引访问快” 的优势,具体特点如下:

  1. 存储结构:底层基于数组,元素在内存中连续存储,通过索引(index,从 0 开始)快速定位元素。
  2. 查询高效:获取指定索引元素(get(int index))的时间复杂度为 O(1),适合频繁查询的场景。
  3. 增删低效
    • 尾部添加元素(add(Object e))效率较高(无扩容时为 O (1));
    • 中间 / 头部增删元素(add(int index, E e)remove(int index))需移动后续元素,时间复杂度为 O(n),不适合频繁增删的场景。
  4. 线程不安全:非同步设计,多线程环境下直接使用可能出现数据安全问题(如需线程安全,可使用 Collections.synchronizedList(new ArrayList<>()) 或替代类 CopyOnWriteArrayList)。
  5. 支持泛型:可通过泛型(如 <String><Integer>)限定存储元素的类型,避免类型转换异常,提升代码安全性。
  6. 自动扩容:初始容量默认 10,当元素数量超过当前容量时,会自动扩容为原来的 1.5 倍(通过 Arrays.copyOf() 复制原数组实现)。

二、ArrayList 常用方法

ArrayList 提供了丰富的方法用于操作元素,以下是开发中最常用的方法,均附完整示例代码,直接复制即可运行。

1. 基础操作:添加、获取、删除

(1)添加元素
  • add(E e):向集合尾部添加元素;
  • add(int index, E e):向集合指定索引位置添加元素(原位置及后续元素后移)。
import java.util.ArrayList;public class ArrayListAddDemo {public static void main(String[] args) {// 泛型限定:集合仅存储 String 类型元素ArrayList<String> list = new ArrayList<>();// 1. 尾部添加元素list.add("Java");list.add("Python");System.out.println("尾部添加后:" + list); // 输出:[Java, Python]// 2. 指定索引添加(索引 1)list.add(1, "Golang");System.out.println("指定索引添加后:" + list); // 输出:[Java, Golang, Python]}
}
(2)获取元素与集合大小
  • get(int index):获取指定索引的元素(索引从 0 开始,越界会抛 IndexOutOfBoundsException);
  • size():返回集合中元素的实际个数(区别于数组的 “容量”)。
public class ArrayListGetSizeDemo {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("北京");list.add("上海");list.add("广州");// 获取索引 1 的元素String city = list.get(1);System.out.println("索引 1 的元素:" + city); // 输出:上海// 获取集合大小int size = list.size();System.out.println("集合元素个数:" + size); // 输出:3}
}
(3)删除元素
  • remove(int index):删除指定索引的元素,返回被删除的元素,后续元素前移;
  • remove(Object o):删除集合中第一次出现的指定元素,返回 booleantrue 表示删除成功,false 表示元素不存在)。
public class ArrayListRemoveDemo {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("苹果");list.add("香蕉");list.add("香蕉");list.add("橙子");// 1. 按索引删除(删除索引 1 的元素)String removedByIndex = list.remove(1);System.out.println("按索引删除的元素:" + removedByIndex); // 输出:香蕉System.out.println("删除后集合:" + list); // 输出:[苹果, 香蕉, 橙子]// 2. 按元素删除(删除第一次出现的“香蕉”)boolean isRemoved = list.remove("香蕉");System.out.println("是否删除成功:" + isRemoved); // 输出:trueSystem.out.println("最终集合:" + list); // 输出:[苹果, 橙子]}
}

2. 进阶操作:修改、判断、清空

(1)修改元素
  • set(int index, E e):用新元素替换指定索引的旧元素,返回被替换的旧元素
public class ArrayListSetDemo {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(10);list.add(20);list.add(30);// 替换索引 1 的元素(20 → 25)Integer oldVal = list.set(1, 25);System.out.println("被替换的旧值:" + oldVal); // 输出:20System.out.println("修改后集合:" + list); // 输出:[10, 25, 30]}
}
(2)判断元素与集合空否
  • contains(Object o):判断集合是否包含指定元素,返回 boolean
  • isEmpty():判断集合是否为空(元素个数为 0),返回 boolean
public class ArrayListJudgeDemo {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("猫");list.add("狗");// 1. 判断是否包含“狗”boolean hasDog = list.contains("狗");System.out.println("是否包含狗:" + hasDog); // 输出:true// 2. 判断集合是否为空boolean isEmpty = list.isEmpty();System.out.println("集合是否为空:" + isEmpty); // 输出:false// 清空集合后再判断list.clear();System.out.println("清空后集合是否为空:" + list.isEmpty()); // 输出:true}
}
(3)清空集合
  • clear():删除集合中所有元素,集合变为空(但对象本身仍存在)。
public class ArrayListClearDemo {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("A");list.add("B");System.out.println("清空前:" + list); // 输出:[A, B]// 清空集合list.clear();System.out.println("清空后:" + list); // 输出:[]System.out.println("清空后大小:" + list.size()); // 输出:0}
}

3. ArrayList 三种遍历方式

遍历是集合的核心操作,ArrayList 支持三种常用遍历方式,需根据场景选择:

(1)普通 for 循环(适合需索引的场景)

通过 size() 获取长度,get(int index) 获取指定索引元素,可手动控制遍历顺序。

public class ArrayListForDemo {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("周一");list.add("周二");list.add("周三");// 普通 for 循环遍历for (int i = 0; i < list.size(); i++) {System.out.println("索引 " + i + ":" + list.get(i));}// 输出:// 索引 0:周一// 索引 1:周二// 索引 2:周三}
}
(2)增强 for 循环(foreach,简洁高效)

无需关注索引,直接遍历每个元素,代码简洁,是日常开发的首选。

public class ArrayListForEachDemo {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("Spring");list.add("MyBatis");list.add("SpringBoot");// 增强 for 循环遍历for (String framework : list) {System.out.println("框架:" + framework);}// 输出:// 框架:Spring// 框架:MyBatis// 框架:SpringBoot}
}
(3)迭代器(Iterator,支持遍历中删除元素)

通过 iterator() 获取迭代器,用 hasNext() 判断是否有下一个元素,next() 获取元素。注意:遍历中删除元素需用 iterator.remove(),而非 list.remove(),否则会抛 ConcurrentModificationException

import java.util.ArrayList;
import java.util.Iterator;public class ArrayListIteratorDemo {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("红色");list.add("绿色");list.add("蓝色");// 迭代器遍历Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String color = iterator.next();// 遍历中删除“绿色”if ("绿色".equals(color)) {iterator.remove(); // 必须用迭代器的 remove() 方法}System.out.println("颜色:" + color);}System.out.println("删除后集合:" + list); // 输出:[红色, 蓝色]}
}

三、ArrayList 使用注意事项

  1. 索引越界问题get(int index)remove(int index) 等方法的索引需在 [0, size()-1] 范围内,否则会抛 IndexOutOfBoundsException,使用前需确认索引合法性。
  2. 泛型与空元素
    • 泛型仅支持引用类型(如 Integer,而非 int);
    • ArrayList 允许存储 null 元素(但不建议,可能导致后续 equals() 判断空指针)。
  3. 线程安全问题:ArrayList 非线程安全,多线程同时读写时,需通过 Collections.synchronizedList() 包装,或使用线程安全的 CopyOnWriteArrayList
  4. 扩容性能优化:若已知集合元素数量,创建 ArrayList 时可指定初始容量(如 new ArrayList<>(100)),减少自动扩容次数(扩容需复制数组,消耗性能)。
  5. 与 LinkedList 的区别:ArrayList 适合查询多、增删少的场景;LinkedList(链表实现)适合增删多、查询少的场景,需根据业务选择。

四、总结

ArrayList 作为 Java 中最常用的集合类,核心是 “动态数组” 的实现,优势在于快速查询,劣势在于中间增删效率低。掌握其核心方法(添加、获取、删除、修改)和三种遍历方式,结合使用注意事项(索引、线程安全、扩容优化),就能在开发中灵活应用。

http://www.xdnf.cn/news/18368.html

相关文章:

  • Redis实战-基于Session实现分布式登录
  • PyTorch API 1
  • PyTorch API 5
  • 372. 超级次方
  • IIS访问报错:HTTP 错误 500.19 - Internal Server Error
  • Spring Retry实战指南_让你的应用更具韧性
  • 区块链技术:重塑未来互联网的伟大动力
  • Python Day32 JavaScript 数组与对象核心知识点整理
  • 源码编译部署 LAMP 架构详细步骤说明
  • Java设计模式-命令模式
  • python的校园顺路代送系统
  • Day 40:训练和测试的规范写法
  • Flink实现Exactly-Once语义的完整技术分解
  • 利用无事务方式插入数据库解决并发插入问题(最小主键id思路)
  • idea进阶技能掌握, 自带HTTP测试工具HTTP client使用方法详解,完全可替代PostMan
  • 暖哇科技AI调查智能体上线,引领保险调查风控智能化升级
  • 【数据结构】排序算法全解析:概念与接口
  • RK android14 Setting一级菜单IR遥控器无法聚焦问题解决方法
  • Apache ShenYu和Nacos之间的通信原理
  • VPS海外节点性能监控全攻略:从基础配置到高级优化
  • Android 入门到实战(三):ViewPager及ViewPager2多页面布局
  • 数据预处理学习心得:从理论到实践的桥梁搭建
  • 比剪映更轻量!SolveigMM 视频无损剪切实战体验
  • 29.Linux rsync+inotify解决同步数据实时性
  • 3D检测笔记:相机模型与坐标变换
  • 详解 scikit-learn 数据预处理工具:从理论到实践
  • CS+ for CC编译超慢的问题该如何解决
  • Day23 双向链表
  • 计算机网络--HTTP协议
  • 亚马逊新品爆单策略:从传统困境到智能突破