第五章 集合框架
第二节 List接口及其实现
概述
集合框架是Java程序设计的重要组成部分,能够有效管理和操作一组对象。第二节重点讲解List接口及其主要实现类,包括ArrayList、LinkedList和Vector。学完本节内容,考生应掌握List接口的定义、特性、常用方法及其不同实现的适用场景,能够灵活运用List操作有序数据集合,满足实际开发需求。
核心概念
- List接口:Java集合框架中的一个接口,继承自Collection,表示一个有序的元素集合,允许元素重复。
- ArrayList:List接口的主要实现类,基于动态数组实现,支持快速随机访问,适合频繁查询操作。
- LinkedList:List接口的另一实现类,基于双向链表实现,适合频繁插入和删除操作。
- Vector:早期实现类,基于动态数组,线程安全,但性能较低,通常被ArrayList替代。
- 迭代器(Iterator):用于遍历集合元素的统一接口。
原理分析
List接口设计为一种有序集合,支持元素下标访问和重复元素存储。其实现类的不同底层结构决定了性能特征和适用场景。ArrayList底层是数组,支持通过索引快速访问元素,但插入和删除操作成本较高,因为可能涉及数组复制和元素移动。LinkedList则是基于链表结构,插入、删除操作效率高,但随机访问效率较低,需要顺序遍历链表节点。Vector与ArrayList类似,但所有方法都同步,保证线程安全,代价是性能下降。
详细内容
1. List接口详解
List接口继承自Collection,定义了有序集合的行为。主要方法包括:
add(int index, E element):在指定位置插入元素get(int index):获取指定位置的元素set(int index, E element):替换指定位置的元素remove(int index):删除指定位置的元素indexOf(Object o)、lastIndexOf(Object o):查找元素位置listIterator():获取支持双向遍历的迭代器
这些方法使List可以灵活操作有序数据,支持通过下标访问和修改。
2. ArrayList详解
ArrayList是最常用的List实现,底层通过Object数组存储元素,初始容量默认为10。其特点:
- 动态扩容:当元素超过当前数组容量时,ArrayList会创建一个更大的数组,将原数组数据复制过去。
- 快速随机访问:因为底层是数组,实现了快速的
get(int index)操作。 - 插入删除性能:在数组中间插入或删除元素时,需要移动后续元素,性能相对较低。
常用构造方法:
ArrayList():默认容量ArrayList(int initialCapacity):指定初始容量ArrayList(Collection<? extends E> c):将另一集合元素添加到列表中
关键方法示例:
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add(1, "C++"); // 在索引1插入C++
String s = list.get(2); // 获取索引2元素
list.remove(0); // 删除第一个元素
3. LinkedList详解
LinkedList基于双向链表实现,节点包含元素和指向前后节点的引用。特点:
- 插入和删除效率高:只需修改节点指针,适合频繁增删操作。
- 随机访问较慢:访问元素时需要从头或尾开始遍历节点,平均时间复杂度O(n)。
- 支持队列和双端队列接口:LinkedList实现了Deque接口,支持队列和栈操作。
关键方法示例:
LinkedList<Integer> linkedList = new LinkedList<>();
linkedList.add(10);
linkedList.addFirst(5); // 添加到开头
linkedList.addLast(20); // 添加到末尾
int val = linkedList.get(1); // 获取索引1元素
linkedList.removeLast(); // 删除最后元素
4. Vector详解
Vector是早期JDK提供的List实现,底层结构与ArrayList类似,但其方法是同步的。特点:
- 线程安全:通过synchronized关键字保证多线程安全
- 性能较低:同步开销大,单线程环境推荐使用ArrayList
由于Vector较老,通常不推荐在新项目中使用。
5. List的遍历方式
- for循环:基于索引访问,适合RandomAccess的List实现如ArrayList
- 增强for循环:简洁,底层使用迭代器遍历
- 迭代器(Iterator):支持删除操作,防止并发修改异常
- ListIterator:支持双向遍历和元素修改
示例代码:
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
for (String s : list) {
System.out.println(s);
}
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
System.out.println(lit.next());
}
实例分析
实例一:学生成绩管理系统
背景:设计一个学生成绩管理系统,需要存储学生成绩并支持按索引快速访问和修改。
分析:学生成绩通常需要快速查询和修改,插入删除操作较少,适合使用ArrayList。
代码示例:
ArrayList<Integer> scores = new ArrayList<>();
scores.add(85);
scores.add(90);
scores.add(78);
// 修改第二个成绩
scores.set(1, 95);
// 遍历打印成绩
for (Integer score : scores) {
System.out.println(score);
}
结论:ArrayList能满足快速访问需求,代码简洁高效。
实例二:任务调度队列
背景:实现一个任务调度系统,任务需要按顺序处理,并且频繁在队首和队尾插入删除任务。
分析:频繁插入删除,且需要双端访问,LinkedList是理想选择。
代码示例:
LinkedList<String> tasks = new LinkedList<>();
tasks.addLast("任务1");
tasks.addLast("任务2");
tasks.addFirst("紧急任务");
// 处理任务
while (!tasks.isEmpty()) {
String task = tasks.removeFirst();
System.out.println("处理: " + task);
}
结论:LinkedList支持双端操作,适合实现队列/双端队列。
实例三:多线程环境下的日志收集
背景:多线程环境下收集日志,需要线程安全的List。
分析:Vector是线程安全的List实现,但性能较低,可以使用Vector或者其他线程安全集合。
代码示例:
Vector<String> logs = new Vector<>();
logs.add("日志1");
logs.add("日志2");
for (String log : logs) {
System.out.println(log);
}
结论:Vector适合简单线程安全需求,但推荐使用更现代的并发集合。
常见误区
误区1:误将ArrayList当成线程安全集合使用
- 正确做法:ArrayList不是线程安全的,多线程环境需自行同步或使用线程安全集合。
误区2:在LinkedList中频繁使用get()方法进行随机访问
- 说明:LinkedList随机访问效率低,应避免频繁使用get(index),改用迭代器遍历。
误区3:使用Vector替代所有List需求
- 说明:Vector性能较低,除非必须线程安全,否则优先使用ArrayList。
误区4:未合理选择List实现,导致性能瓶颈
- 建议:根据操作特点选择ArrayList或LinkedList,避免盲目使用。
误区5:修改集合时未使用迭代器的remove方法,导致ConcurrentModificationException
- 解决方案:使用Iterator的remove方法安全删除元素。
应用场景
场景1:数据展示列表
- 适用ArrayList,支持快速随机访问和遍历。
场景2:任务调度和消息队列
- 适用LinkedList,频繁增删效率高。
场景3:多线程日志收集
- 适用Vector或CopyOnWriteArrayList,保证线程安全。
场景4:浏览器历史记录管理
- 适合LinkedList实现双向遍历和快速插入删除。
场景5:动态数据缓存
- ArrayList适合缓存大量数据,便于快速访问。
知识拓展
- CopyOnWriteArrayList:一种线程安全的List实现,读多写少场景下性能优异,底层通过复制数组实现写时复制。
- Collections.synchronizedList(List
list) :通过包装器实现线程安全的List。 - List接口的默认方法:Java 8引入的
replaceAll、sort等默认方法,增强了List操作能力。 - Java 9+ List.of():创建不可变List集合,保证数据安全和不变性。
总结回顾
本节重点介绍了Java集合框架中的List接口及其主要实现类ArrayList、LinkedList、Vector。通过对接口定义、底层结构、性能特点进行详细分析,帮助考生理解不同实现的适用场景和使用技巧。掌握List常用方法及遍历方式,避免常见误区,能够根据实际需求选择合适的List实现类。结合典型案例,强化理论与实践结合,为全国计算机等级考试二级Java语言程序设计的集合框架部分打下坚实基础。
本节核心知识点回顾:
- List接口是有序、可重复元素集合的基础接口
- ArrayList基于动态数组,支持快速随机访问
- LinkedList基于双向链表,适合频繁插入和删除
- Vector线程安全但性能低,已被ArrayList取代
- 合理选择List实现类,提升程序性能与效率
- 常用遍历方式包括for循环、增强for、Iterator和ListIterator
- 多线程环境需注意集合的线程安全问题