目录
- 核心概念与特点
- 构造方法
- 核心操作方法
- 添加元素
- 删除元素
- 获取元素
- 修改元素
- 查询判断
- 遍历方法
- 工具方法
- 性能分析
- 代码示例
核心概念与特点
在深入方法之前,理解 ArrayList 的本质很重要:

- 动态数组:它的底层是一个数组,当元素数量超过数组容量时,它会创建一个更大的新数组,并将旧数组的元素复制到新数组中(这个过程称为扩容)。
- 优点:
- 随机访问快:通过索引访问元素的时间复杂度是 O(1)。
- 尾部添加/删除快:在列表末尾添加或删除元素,时间复杂度是 O(1)(不考虑扩容)。
- 缺点:
- 中间插入/删除慢:在列表中间插入或删除元素,需要移动大量元素,时间复杂度是 O(n)。
- 扩容有开销:当容量不足时,扩容操作会消耗时间和内存。
构造方法
在创建 ArrayList 实例时,有几种构造方式:
import java.util.ArrayList;
import java.util.List;
public class ArrayListConstructor {
public static void main(String[] args) {
// 1. 默认构造函数:创建一个初始容量为 10 的空列表
List<String> list1 = new ArrayList<>();
System.out.println("默认容量: " + ((ArrayList<?>) list1).size()); // 输出 0
// 注意:ArrayList没有直接获取容量的public方法,但源码中是10
// 2. 指定初始容量的构造函数:适用于已知大概元素数量,避免频繁扩容
List<Integer> list2 = new ArrayList<>(20);
System.out.println("指定容量列表初始大小: " + list2.size()); // 输出 0
// 3. 使用另一个集合初始化:新列表包含指定集合的所有元素
List<String> existingList = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> list3 = new ArrayList<>(existingList);
System.out.println("使用集合初始化: " + list3); // 输出 [A, B, C]
}
}
核心操作方法
这是 ArrayList 最常用的一组方法。
添加元素
| 方法 | 描述 | 时间复杂度 | 示例 |
|---|---|---|---|
add(E e) |
将元素 e 追加到列表的末尾。 |
O(1) (均摊) | list.add("Apple"); |
add(int index, E e) |
将元素 e 插入到列表的指定 index 位置。 |
O(n) | list.add(1, "Banana"); |
addAll(Collection<? extends E> c) |
将集合 c 中的所有元素追加到列表末尾。 |
O(m) (m为集合c的大小) | list.addAll(Arrays.asList("Cherry", "Date")); |
addAll(int index, Collection<? extends E> c) |
将集合 c 中的所有元素插入到列表的指定 index 位置。 |
O(n + m) | list.addAll(2, anotherList); |
删除元素
| 方法 | 描述 | 时间复杂度 | 示例 |
|---|---|---|---|
remove(Object o) |
删除列表中第一个出现的元素 o,如果元素不存在,则不改变列表。 |
O(n) | list.remove("Apple"); |
remove(int index) |
删除列表中指定 index 位置的元素,并返回被删除的元素。 |
O(n) | String removed = list.remove(0); |
clear() |
清空列表,移除所有元素。 | O(n) (在某些JVM实现中) | list.clear(); |
获取元素
| 方法 | 描述 | 时间复杂度 | 示例 |
|---|---|---|---|
get(int index) |
返回列表中指定 index 位置的元素。 |
O(1) | String fruit = list.get(0); |
size() |
返回列表中的元素数量。 | O(1) | int count = list.size(); |
修改元素
| 方法 | 描述 | 时间复杂度 | 示例 |
|---|---|---|---|
set(int index, E e) |
用元素 e 替换列表中指定 index 位置的元素,并返回被替换掉的旧元素。 |
O(1) | String oldFruit = list.set(0, "Apricot"); |
查询判断
| 方法 | 描述 | 时间复杂度 | 示例 |
|---|---|---|---|
contains(Object o) |
如果列表中包含元素 o,则返回 true。 |
O(n) | boolean hasBanana = list.contains("Banana"); |
isEmpty() |
如果列表不包含任何元素,则返回 true。 |
O(1) | boolean empty = list.isEmpty(); |
indexOf(Object o) |
返回元素 o 在列表中第一次出现的索引,如果列表不包含该元素,则返回 -1。 |
O(n) | int index = list.indexOf("Banana"); |
lastIndexOf(Object o) |
返回元素 o 在列表中最后一次出现的索引,如果列表不包含该元素,则返回 -1。 |
O(n) | int lastIndex = list.lastIndexOf("Banana"); |
遍历方法
遍历 ArrayList 有多种方式,各有优劣。
for-each 循环 (推荐)
最简洁、最常用的方式,适用于只读遍历。

for (String fruit : list) {
System.out.println(fruit);
}
传统 for 循环
当需要知道元素的索引时使用。
for (int i = 0; i < list.size(); i++) {
String fruit = list.get(i);
System.out.println("Index " + i + ": " + fruit);
}
使用迭代器 (Iterator)
这是最安全、最标准的遍历方式,尤其是在遍历过程中需要删除元素时。
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
if ("Banana".equals(fruit)) {
iterator.remove(); // 安全地删除当前元素
}
}
注意:在迭代过程中,不能使用 list.remove() 方法,否则会抛出 ConcurrentModificationException,必须使用迭代器自己的 remove() 方法。
使用 Java 8 Stream API (函数式风格)
适合进行复杂的链式操作、过滤、转换等。

list.stream()
.filter(fruit -> !fruit.startsWith("A")) // 过滤掉以A开头的元素
.forEach(System.out::println); // 打印剩余元素
工具方法
| 方法 | 描述 |
|---|---|
toArray() |
将列表转换为一个Object 类型的数组。 |
toArray(T[] a) |
将列表转换为一个指定类型的数组,这是更常用的重载方法。 |
clone() |
创建 ArrayList 的浅拷贝。 |
toArray 示例:
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
// 1. 转换为 Object 数组
Object[] objArray = list.toArray();
System.out.println(Arrays.toString(objArray)); // [A, B, C]
// 2. 转换为指定类型的数组 (推荐方式)
String[] strArray = list.toArray(new String[0]);
System.out.println(Arrays.toString(strArray)); // [A, B, C]
// 如果指定数组长度不够,会创建一个新数组
String[] strArray2 = list.toArray(new String[5]);
System.out.println(Arrays.toString(strArray2)); // [A, B, C, null, null]
性能分析总结
| 操作 | 时间复杂度 | 原因 |
|---|---|---|
add(E e) (尾部添加) |
O(1) (均摊) | 大部分情况下是直接在数组末尾添加,只有在扩容时,需要复制所有元素,所以是均摊的 O(1)。 |
add(int index, E e) (中间插入) |
O(n) | 需要将 index 位置之后的所有元素都向后移动一位。 |
remove(int index) (中间删除) |
O(n) | 需要将 index 位置之后的所有元素都向前移动一位。 |
get(int index) |
O(1) | 直接通过索引计算数组位置,访问速度极快。 |
set(int index, E e) |
O(1) | 同 get,直接通过索引定位并修改。 |
contains(Object o) |
O(n) | 需要遍历整个数组,逐个比较。 |
remove(Object o) |
O(n) | 需要先遍历找到元素,再进行移动。 |
ArrayList非常适合:需要频繁随机访问元素,或者主要在列表末尾进行增删操作的场景。ArrayList不适合:需要在列表中间频繁插入或删除元素的场景,LinkedList会是更好的选择。
完整代码示例
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class ArrayListMethodsDemo {
public static void main(String[] args) {
// 1. 创建和初始化
List<String> fruits = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
System.out.println("初始列表: " + fruits);
// 2. 添加元素
fruits.add("Date"); // 尾部添加
System.out.println("添加 Date 后: " + fruits);
fruits.add(1, "Blueberry"); // 中间插入
System.out.println("在索引 1 插入 Blueberry 后: " + fruits);
// 3. 获取元素
String firstFruit = fruits.get(0);
System.out.println("第一个水果是: " + firstFruit);
// 4. 修改元素
String oldFruit = fruits.set(2, "Cantaloupe");
System.out.println("将索引 2 的 " + oldFruit + " 替换为 Cantaloupe 后: " + fruits);
// 5. 查询判断
System.out.println("列表是否包含 Banana? " + fruits.contains("Banana"));
System.out.println("Banana 的索引是: " + fruits.indexOf("Banana"));
System.out.println("列表大小: " + fruits.size());
// 6. 删除元素
fruits.remove("Date"); // 删除特定元素
System.out.println("删除 Date 后: " + fruits);
String removedFruit = fruits.remove(0); // 按索引删除
System.out.println("删除索引 0 的 " + removedFruit + " 后: " + fruits);
// 7. 遍历
System.out.println("--- 使用 for-each 遍历 ---");
for (String fruit : fruits) {
System.out.println(fruit);
}
System.out.println("--- 使用迭代器遍历并删除 ---");
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
if (fruit.startsWith("B")) {
iterator.remove(); // 安全删除
}
}
System.out.println("删除所有以 B 开头的元素后: " + fruits);
// 8. 清空
fruits.clear();
System.out.println("清空列表后: " + fruits);
System.out.println("列表是否为空? " + fruits.isEmpty());
}
} 