目录一、认识List不仅仅是“列表”1.1 从生活场景说起1.2 List在Java家族中的地位1.3 从数据结构角度看List二、List的核心方法详解2.1 增删改查四大基本操作增加元素删除元素修改元素查询元素2.2 其他实用方法2.3 三种遍历方式三、List的实现类ArrayList vs LinkedList3.1 快速对比3.2 什么时候选ArrayList3.3 什么时候选LinkedList3.4 一个真实的性能对比实验四、实战用List实现一个简易的学生管理系统五、避坑指南List使用中的常见问题5.1 并发修改异常5.2 Arrays.asList的坑5.3 基本类型与泛型六、总结与学习建议6.1 核心要点回顾6.2 学习建议写在前面本文基于《List的介绍》课程内容整理结合个人学习心得与实践经验编写。文中所有示例代码均为独立编写旨在帮助读者建立对List体系的系统认知。如需深入学习建议配合Oracle官方文档和JDK源码阅读。一、认识List不仅仅是“列表”1.1 从生活场景说起想象你正在管理一个班级的花名册学生按学号排列有序允许同名同学存在可重复可以随时查看第几个是谁索引访问可以新增、删除、修改学生信息这不就是List最形象的写照吗List就是一组有序、可重复的数据集合每个元素都有自己的位置编号索引。1.2 List在Java家族中的地位在Java集合框架中List是一个接口它继承自Collection接口而Collection又继承自Iterable接口。Iterable (可迭代) ↑ Collection (集合) ↑ List (列表) ↑ ArrayList / LinkedList (实现类)为什么要设计这么多层 这是为了最大程度地解耦。上层接口定义“做什么”下层实现类决定“怎么做”。你只需要学会使用List接口的方法不管底层是ArrayList还是LinkedList用法都是一致的。1.3 从数据结构角度看List站在数据结构的角度List本质上就是一个线性表——n个具有相同类型元素的有限序列。线性表的特点元素之间有先后顺序除了第一个和最后一个每个元素都有唯一的前驱和后继可以通过索引快速定位二、List的核心方法详解虽然List接口定义了30多个方法但日常开发中常用的也就十几个。我把它们分为几类方便你记忆。2.1 增删改查四大基本操作增加元素ListString list new ArrayList(); // 1. 尾部追加 list.add(Java); list.add(Python); // 2. 指定位置插入 list.add(1, C); // 在索引1处插入后面的元素自动后移 // 3. 批量追加 ListString others Arrays.asList(Go, Rust); list.addAll(others); System.out.println(list); // 输出[Java, C, Python, Go, Rust]注意add(int index, E element)在插入时index必须在[0, size]范围内否则会抛出IndexOutOfBoundsException。删除元素ListString list new ArrayList(Arrays.asList(A, B, C, B)); // 1. 按索引删除 String removed list.remove(1); // 删除索引1处的B System.out.println(removed); // B System.out.println(list); // [A, C, B] // 2. 按对象删除删除第一次出现的 boolean success list.remove(B); System.out.println(success); // true System.out.println(list); // [A, C] // 3. 批量删除 ListString toRemove Arrays.asList(A, C); list.removeAll(toRemove); System.out.println(list); // []一个常见的坑当List存储的是Integer时remove(1)到底是删除索引1还是删除值为1的元素ListInteger numbers new ArrayList(Arrays.asList(10, 20, 30)); numbers.remove(1); // ❌ 删除索引1处的元素结果是[10, 30] numbers.remove(Integer.valueOf(1)); // ✅ 删除值为1的元素记住remove(int index)是重载方法传入int时优先匹配索引版本。修改元素ListString list new ArrayList(Arrays.asList(A, B, C)); // set方法返回旧值 String oldValue list.set(1, NewB); System.out.println(oldValue); // B System.out.println(list); // [A, NewB, C]查询元素ListString list Arrays.asList(Apple, Banana, Cherry, Banana); // 1. 按索引获取 String fruit list.get(2); System.out.println(fruit); // Cherry // 2. 判断是否存在 boolean hasApple list.contains(Apple); System.out.println(hasApple); // true // 3. 查找元素位置 int firstIndex list.indexOf(Banana); int lastIndex list.lastIndexOf(Banana); System.out.println(firstIndex); // 1 System.out.println(lastIndex); // 3 // 4. 找不到时返回-1 int notFound list.indexOf(Grape); System.out.println(notFound); // -12.2 其他实用方法ListString list new ArrayList(Arrays.asList(A, B, C)); // 获取大小 int size list.size(); // 判断是否为空 boolean isEmpty list.isEmpty(); // 清空列表 list.clear(); // 截取子列表注意视图而非副本 ListString sub list.subList(0, 2); // 包含0不包含2subList的重要提醒它返回的是原列表的视图而不是新创建的副本。对子列表的修改会直接影响原列表。ListString original new ArrayList(Arrays.asList(A, B, C, D)); ListString sub original.subList(1, 3); // [B, C] sub.set(0, Modified); System.out.println(original); // [A, Modified, C, D] ← 原列表也被改了如果需要独立的副本应该新建一个ArrayListListString copy new ArrayList(original.subList(1, 3));2.3 三种遍历方式ListString list Arrays.asList(Java, Python, Go); // 方式一for循环 索引 for (int i 0; i list.size(); i) { System.out.println(list.get(i)); } // 方式二增强for循环 for (String lang : list) { System.out.println(lang); } // 方式三迭代器 IteratorString it list.iterator(); while (it.hasNext()) { System.out.println(it.next()); }三种方式的适用场景需要索引时用方式一只遍历不改动时用方式二最简洁需要在遍历时删除元素时用方式三用it.remove()三、List的实现类ArrayList vs LinkedListList只是一个接口不能直接实例化。最常用的两个实现类是ArrayList和LinkedList。3.1 快速对比特性ArrayListLinkedList底层结构动态数组双向链表随机访问(get/set)O(1) ⭐O(n)尾部插入(add)O(1)O(1)头部/中间插入O(n)O(1) ⭐内存占用较少较多存储前后指针适用场景频繁读取频繁插入删除3.2 什么时候选ArrayList// ✅ 适合的场景频繁读取、尾部追加 ListString readHeavyList new ArrayList(); readHeavyList.add(数据1); readHeavyList.add(数据2); // ... 批量加载数据 // 后续主要进行读取操作 String data readHeavyList.get(500000); // 毫秒级响应3.3 什么时候选LinkedList// ✅ 适合的场景频繁在头部或中间插入删除 ListString writeHeavyList new LinkedList(); writeHeavyList.add(A); writeHeavyList.add(B); writeHeavyList.addFirst(HEAD); // 头部插入LinkedList特有 writeHeavyList.addLast(TAIL); // 尾部插入 // 模拟队列操作 writeHeavyList.removeFirst(); // 移除头部3.4 一个真实的性能对比实验// 测试在列表头部插入10万条数据 long startTime System.currentTimeMillis(); ListInteger arrayList new ArrayList(); for (int i 0; i 100000; i) { arrayList.add(0, i); // 每次都插入头部 } System.out.println(ArrayList耗时: (System.currentTimeMillis() - startTime) ms); startTime System.currentTimeMillis(); ListInteger linkedList new LinkedList(); for (int i 0; i 100000; i) { linkedList.add(0, i); // 每次都插入头部 } System.out.println(LinkedList耗时: (System.currentTimeMillis() - startTime) ms);在我的机器上结果大概是ArrayList约3000msLinkedList约10ms差距悬殊所以在选择实现类时一定要考虑你的主要操作模式。四、实战用List实现一个简易的学生管理系统把学到的知识串联起来我们写一个小程序import java.util.*; public class StudentManager { private ListString students; public StudentManager() { this.students new ArrayList(); } // 添加学生 public void addStudent(String name) { students.add(name); System.out.println(添加成功 name); } // 删除学生 public void removeStudent(String name) { if (students.remove(name)) { System.out.println(删除成功 name); } else { System.out.println(未找到学生 name); } } // 修改学生姓名 public void updateStudent(int index, String newName) { if (index 0 index students.size()) { String oldName students.set(index, newName); System.out.println(已将 oldName 改为 newName); } else { System.out.println(索引无效); } } // 查询学生 public void searchStudent(String name) { int index students.indexOf(name); if (index ! -1) { System.out.println(name 在索引 index 处); } else { System.out.println(未找到 name); } } // 打印所有学生 public void printAll() { if (students.isEmpty()) { System.out.println(暂无学生信息); return; } System.out.println( 学生列表 ); for (int i 0; i students.size(); i) { System.out.println((i 1) . students.get(i)); } } public static void main(String[] args) { StudentManager manager new StudentManager(); manager.addStudent(张三); manager.addStudent(李四); manager.addStudent(王五); manager.printAll(); manager.searchStudent(李四); manager.updateStudent(0, 张大大); manager.removeStudent(王五); manager.printAll(); } }运行结果添加成功张三 添加成功李四 添加成功王五 学生列表 1. 张三 2. 李四 3. 王五 李四在索引1处 已将张三改为张大大 删除成功王五 学生列表 1. 张大大 2. 李四五、避坑指南List使用中的常见问题5.1 并发修改异常ListString list new ArrayList(Arrays.asList(A, B, C)); // ❌ 错误在遍历时修改 for (String s : list) { if (B.equals(s)) { list.remove(s); // 抛出ConcurrentModificationException } } // ✅ 正确使用迭代器的remove方法 IteratorString it list.iterator(); while (it.hasNext()) { String s it.next(); if (B.equals(s)) { it.remove(); } }5.2 Arrays.asList的坑ListString list Arrays.asList(A, B, C); // ❌ 错误asList返回的是固定大小的列表 list.add(D); // 抛出UnsupportedOperationException list.remove(A); // 抛出UnsupportedOperationException // ✅ 正确如果想修改重新包装 ListString mutableList new ArrayList(Arrays.asList(A, B, C)); mutableList.add(D); // 正常5.3 基本类型与泛型// ❌ 错误泛型不能是基本类型 Listint wrongList new ArrayList(); // ✅ 正确使用包装类 ListInteger rightList new ArrayList(); rightList.add(100); // 自动装箱 int value rightList.get(0); // 自动拆箱六、总结与学习建议6.1 核心要点回顾List是有序、可重复的线性表继承自Collection核心方法add、remove、get、set、contains、indexOf、subList两种实现ArrayList数组适合读多写少和LinkedList链表适合写多读少遍历方式普通for、增强for、迭代器各有适用场景常见陷阱remove的索引/对象混淆、subList的视图特性、并发修改异常6.2 学习建议多动手写代码只看不练等于没学试着把上面的示例自己敲一遍善用调试用IDE的Debug功能观察列表的变化过程阅读源码打开IDE看看ArrayList和LinkedList的源码你会学到很多精妙的设计如果你觉得这篇文章对你有帮助欢迎点赞收藏。下一篇我们将深入ArrayList的源码看看动态数组的扩容机制和性能优化细节敬请期待注本文为个人学习总结所有代码示例均为独立编写。建议读者在学习过程中结合JDK官方文档和源码进行验证。