在 Java 集合框架中,ArrayList 是 List 接口最常用的实现类之一,因其查询效率高、使用灵活的特点,广泛应用于日常开发。本文将从 ArrayList 的核心特点、常用方法、遍历方式到使用注意事项,进行系统性梳理,帮助快速复习并掌握其核心用法。
一、ArrayList 核心特点
ArrayList 本质是动态数组(底层基于数组实现),相比普通数组,它能自动扩容以存储更多元素,同时保留了数组 "按索引访问快" 的优势,具体特点如下:
- 存储结构 :底层基于数组,元素在内存中连续存储,通过索引(
index
,从 0 开始)快速定位元素。 - 查询高效 :获取指定索引元素(
get(int index)
)的时间复杂度为 O(1),适合频繁查询的场景。 - 增删低效 :
- 尾部添加元素(
add(Object e)
)效率较高(无扩容时为 O (1)); - 中间 / 头部增删元素(
add(int index, E e)
、remove(int index)
)需移动后续元素,时间复杂度为 O(n),不适合频繁增删的场景。
- 尾部添加元素(
- 线程不安全 :非同步设计,多线程环境下直接使用可能出现数据安全问题(如需线程安全,可使用
Collections.synchronizedList(new ArrayList<>())
或替代类CopyOnWriteArrayList
)。 - 支持泛型 :可通过泛型(如
<String>
、<Integer>
)限定存储元素的类型,避免类型转换异常,提升代码安全性。 - 自动扩容 :初始容量默认 10,当元素数量超过当前容量时,会自动扩容为原来的 1.5 倍 (通过
Arrays.copyOf()
复制原数组实现)。
二、ArrayList 常用方法
ArrayList 提供了丰富的方法用于操作元素,以下是开发中最常用的方法,均附完整示例代码,直接复制即可运行。
1. 基础操作:添加、获取、删除
(1)添加元素
add(E e)
:向集合尾部添加元素;add(int index, E e)
:向集合指定索引位置添加元素(原位置及后续元素后移)。
java
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()
:返回集合中元素的实际个数(区别于数组的 "容量")。
java
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)
:删除集合中第一次出现 的指定元素,返回boolean
(true
表示删除成功,false
表示元素不存在)。
java
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); // 输出:true
System.out.println("最终集合:" + list); // 输出:[苹果, 橙子]
}
}
2. 进阶操作:修改、判断、清空
(1)修改元素
set(int index, E e)
:用新元素替换指定索引的旧元素,返回被替换的旧元素。
java
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); // 输出:20
System.out.println("修改后集合:" + list); // 输出:[10, 25, 30]
}
}
(2)判断元素与集合空否
contains(Object o)
:判断集合是否包含指定元素,返回boolean
;isEmpty()
:判断集合是否为空(元素个数为 0),返回boolean
。
java
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()
:删除集合中所有元素,集合变为空(但对象本身仍存在)。
java
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)
获取指定索引元素,可手动控制遍历顺序。
java
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,简洁高效)
无需关注索引,直接遍历每个元素,代码简洁,是日常开发的首选。
java
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
。
java
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 使用注意事项
- 索引越界问题 :
get(int index)
、remove(int index)
等方法的索引需在[0, size()-1]
范围内,否则会抛IndexOutOfBoundsException
,使用前需确认索引合法性。 - 泛型与空元素 :
- 泛型仅支持引用类型(如
Integer
,而非int
); - ArrayList 允许存储
null
元素(但不建议,可能导致后续equals()
判断空指针)。
- 泛型仅支持引用类型(如
- 线程安全问题 :ArrayList 非线程安全,多线程同时读写时,需通过
Collections.synchronizedList()
包装,或使用线程安全的CopyOnWriteArrayList
。 - 扩容性能优化 :若已知集合元素数量,创建 ArrayList 时可指定初始容量(如
new ArrayList<>(100)
),减少自动扩容次数(扩容需复制数组,消耗性能)。 - 与 LinkedList 的区别 :ArrayList 适合查询多、增删少 的场景;LinkedList(链表实现)适合增删多、查询少的场景,需根据业务选择。
四、总结
ArrayList 作为 Java 中最常用的集合类,核心是 "动态数组" 的实现,优势在于快速查询,劣势在于中间增删效率低。掌握其核心方法(添加、获取、删除、修改)和三种遍历方式,结合使用注意事项(索引、线程安全、扩容优化),就能在开发中灵活应用。