第 12 章:List 接口与 ArrayList
学习目标
- 掌握 List 接口的核心方法
- 理解 ArrayList 和 LinkedList 的选型
- 避开 List 的常见坑
一、List 接口:有序、可重复
java
List<String> list = new ArrayList<>();
list.add("A"); // ① 末尾添加
list.add(0, "B"); // ② 指定位置插入
list.get(0); // ③ 按索引访问
list.set(0, "C"); // ④ 修改
list.remove(0); // ⑤ 按索引删除
list.remove("A"); // ⑥ 按内容删除(删第一个匹配的)
list.size(); // ⑦ 长度
list.contains("A"); // ⑧ 是否包含
list.indexOf("A"); // ⑨ 第一次出现的索引
list.isEmpty(); // ⑩ 是否为空
list.clear(); // 清空遍历(三种方式):
java
List<String> list = List.of("A", "B", "C");
// ① for-each(只读,推荐)
for (String s : list) {
System.out.println(s);
}
// ② 普通 for(需要索引时)
for (int i = 0; i < list.size(); i++) {
System.out.println(i + ": " + list.get(i));
}
// ③ forEach + Lambda(Java 8+)
list.forEach(s -> System.out.println(s));二、ArrayList vs LinkedList
| 维度 | ArrayList | LinkedList |
|---|---|---|
| 底层 | 动态数组 | 双向链表 |
| 随机访问(get) | O(1) 快 | O(n) 慢 |
| 插入/删除 | O(n) 慢 | O(1) 快 |
| 内存占用 | 少 | 多(每个节点 2 个指针) |
⚠️ 坑 1:99% 的场景用 ArrayList,除非是队列/栈等频繁增删两端元素的场景才用 LinkedList。
javaList<User> users = new ArrayList<>(); // ✅ 默认 Queue<Task> tasks = new LinkedList<>(); // ⚠️ 队列才用
三、ArrayList 常用 API 速查
java
List<Integer> nums = new ArrayList<>(List.of(3, 1, 4, 1, 5));
nums.add(2); // 末尾加
nums.add(0, 9); // 头部加
nums.get(0); // 取第 0 个
nums.set(0, 10); // 改第 0 个
nums.remove(0); // 删第 0 个(返回被删元素)
nums.remove(Integer.valueOf(1)); // 删第一个等于 1 的(注意装箱)
nums.size();
nums.contains(5);
Collections.sort(nums); // 排序
Collections.reverse(nums); // 反转
Collections.shuffle(nums); // 随机打乱⚠️ 坑 2:
list.remove(0)是按索引删;list.remove(Integer.valueOf(0))才是按内容删。直接list.remove(0)会把 0 当索引。
四、List 的常见坑
1. 遍历时修改
java
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
// ❌ ConcurrentModificationException
for (Integer n : list) {
if (n == 2) list.remove(n); // 遍历时删除会抛异常
}
// ✅ 用迭代器
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
if (it.next() == 2) it.remove();
}
// ✅ 或反向遍历删除
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i) == 2) list.remove(i);
}2. Arrays.asList 是固定大小
java
List<String> list = Arrays.asList("a", "b", "c");
list.add("d"); // ❌ UnsupportedOperationException
// ✅ 包一层 ArrayList 才是可变
List<String> mutable = new ArrayList<>(Arrays.asList("a", "b", "c"));
mutable.add("d");3. List.of 不可变
java
List<String> list = List.of("a", "b", "c");
list.set(0, "x"); // ❌ UnsupportedOperationException
// 要可变?自己 new ArrayList<>()五、本章小结
| 要点 | 关键 |
|---|---|
| List 特性 | 有序、可重复、可按索引访问 |
| ArrayList | 99% 场景用,随机访问快 |
| LinkedList | 仅队列/栈等场景用 |
| 遍历时删除 | 用 Iterator 或反向遍历 |
| Arrays.asList | 长度固定,add/remove 会抛异常,可以set |
| List.of | 不可变,完全不能改 |
动手练习
- 学生列表:用 ArrayList 存 5 个学生,实现按名字查找、按成绩排序
- 删除偶数:写一个
removeEven(List<Integer>),注意遍历删除的坑 - 求最大值:用 List + for-each 求
List<Double>的最大值
下一章:第 13 章:Set 接口与 HashSet →