第49章 Java List接口
面包屑导航 章节标题 学习目标
学习目标
- 掌握List接口的基本特性和常用方法
- 理解ArrayList的实现原理和性能特点
- 学会LinkedList的使用场景和双端队列特性
- 了解Vector的线程安全特性
- 掌握不同List实现类的选择原则
- 学会在实际项目中合理使用List集合
List接口概述
List接口概述
List接口是Java集合框架中最重要的接口之一,它继承自Collection接口,表示一个有序的集合。List接口定义了一系列操作有序集合的方法,是ArrayList、LinkedList、Vector等实现类的基础。
有序性
List中的元素按照插入顺序存储,每个元素都有一个确定的位置索引。
可重复
List允许存储重复的元素,同一个对象可以在List中出现多次。
索引访问
支持通过索引直接访问、修改和删除指定位置的元素。
动态大小
List的大小可以动态增长和缩减,不需要预先指定容量。
List接口的常用方法
// 添加元素
boolean add(E e) // 在末尾添加元素
void add(int index, E element) // 在指定位置插入元素
// 获取元素
E get(int index) // 获取指定位置的元素
// 修改元素
E set(int index, E element) // 替换指定位置的元素
// 删除元素
E remove(int index) // 删除指定位置的元素
boolean remove(Object o) // 删除指定对象
// 查找元素
int indexOf(Object o) // 查找元素第一次出现的位置
int lastIndexOf(Object o) // 查找元素最后一次出现的位置
boolean contains(Object o) // 判断是否包含指定元素
// 其他操作
int size() // 获取元素个数
boolean isEmpty() // 判断是否为空
void clear() // 清空所有元素
List subList(int from, int to) // 获取子列表
ArrayList详解
ArrayList详解
ArrayList是List接口最常用的实现类,基于动态数组实现,提供了高效的随机访问能力。
ArrayList的核心特性底层实现:基于Object[]数组,支持动态扩容随机访问:通过索引访问元素的时间复杂度为O(1)插入删除:在末尾操作效率高,中间操作需要移动元素内存效率:连续内存存储,空间利用率高线程安全:非线程安全,多线程环境需要外部同步
ArrayList扩容机制
// ArrayList扩容示例
ArrayList list = new ArrayList<>(); // 默认初始容量为10
// 当元素数量超过当前容量时,会触发扩容
// 新容量 = 旧容量 + (旧容量 >> 1) // 即增长50%
// 建议:如果知道大概大小,可以指定初始容量
ArrayList optimizedList = new ArrayList<>(1000);
LinkedList详解
LinkedList详解
LinkedList基于双向链表实现,在插入和删除操作方面具有优势,同时实现了Deque接口,可以作为栈或队列使用。
LinkedList的核心特性底层实现:基于双向链表,每个节点包含数据和前后指针插入删除:在已知节点位置时,插入删除的时间复杂度为O(1)随机访问:需要从头或尾遍历,时间复杂度为O(n)内存开销:每个节点需要额外存储指针,内存开销较大双端队列:实现了Deque接口,支持栈和队列操作
LinkedList作为双端队列
LinkedList deque = new LinkedList<>();
// 作为栈使用(LIFO - 后进先出)
deque.push(1); // 入栈
deque.push(2);
int top = deque.pop(); // 出栈
// 作为队列使用(FIFO - 先进先出)
deque.offer(10); // 入队
deque.offer(20);
int front = deque.poll(); // 出队
// 双端操作
deque.offerFirst(100); // 头部添加
deque.offerLast(200); // 尾部添加
int first = deque.pollFirst(); // 头部取出
int last = deque.pollLast(); // 尾部取出
性能对比
性能对比分析
不同的List实现类在各种操作上的性能表现差异很大,选择合适的实现类对程序性能至关重要。
| 操作类型 | ArrayList | LinkedList | Vector | 说明 |
|---|---|---|---|---|
| 随机访问 | O(1) | O(n) | O(1) | ArrayList和Vector基于数组,支持直接索引访问 |
| 尾部添加 | O(1)* | O(1) | O(1)* | *可能触发扩容,最坏情况O(n) |
| 中间插入 | O(n) | O(1)** | O(n) | **如果已知节点位置 |
| 删除元素 | O(n) | O(1)** | O(n) | **如果已知节点位置 |
| 内存占用 | 低 | 高 | 低 | LinkedList每个节点需要额外存储指针 |
| 线程安全 | 否 | 否 | 是 | Vector的方法使用synchronized修饰 |
使用场景建议
使用场景建议
ArrayList适用场景
- 需要频繁随机访问元素
- 主要在尾部添加/删除元素
- 对内存使用效率要求高
- 单线程环境或有外部同步
- 读操作远多于写操作
LinkedList适用场景
- 需要频繁在中间插入/删除元素
- 实现栈、队列等数据结构
- 不需要随机访问元素
- 列表大小变化频繁
- 需要双端队列功能
Vector适用场景
- 需要线程安全的List
- 兼容旧版本Java代码
- 简单的多线程场景
- 性能要求不高的应用
- 遗留系统维护
代码示例
完整代码示例
以下是一个综合性的List接口使用示例,展示了不同实现类的特性和使用方法:
import java.util.*;
/**
* List接口综合示例
* 演示ArrayList、LinkedList和Vector的使用
*/
public class ListComprehensiveExample {
public static void main(String[] args) {
// 演示List的基本特性
demonstrateListFeatures();
// 比较不同实现类的性能
comparePerformance();
// 演示实际应用场景
demonstrateRealWorldUsage();
}
/**
* 演示List接口的基本特性
*/
private static void demonstrateListFeatures() {
System.out.println("=== List基本特性演示 ===");
List fruits = new ArrayList<>();
// 1. 有序性:按插入顺序存储
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("橙子");
System.out.println("插入顺序: " + fruits);
// 2. 可重复:允许重复元素
fruits.add("苹果"); // 重复元素
System.out.println("允许重复: " + fruits);
// 3. 索引访问:通过索引获取元素
System.out.println("索引0的元素: " + fruits.get(0));
System.out.println("索引2的元素: " + fruits.get(2));
// 4. 动态大小
System.out.println("当前大小: " + fruits.size());
fruits.remove("香蕉");
System.out.println("删除后大小: " + fruits.size());
}
}
💻 查看完整代码 - 在线IDE体验 最佳实践
最佳实践建议
选择合适的实现类默认选择:大多数情况下使用ArrayList频繁插入删除:考虑使用LinkedList线程安全需求:使用Collections.synchronizedList()或CopyOnWriteArrayList性能优化:合理设置ArrayList的初始容量
常见陷阱和注意事项遍历时修改:避免在增强for循环中修改List,使用Iterator.remove()索引越界:访问元素前检查索引范围null值处理:List允许null值,注意空指针异常equals方法:自定义对象需要正确实现equals和hashCode方法
本章小结
本章小结
- List接口是Java集合框架的核心接口,提供有序、可重复、支持索引访问的集合
- ArrayList基于动态数组实现,适合随机访问和尾部操作,是最常用的List实现
- LinkedList基于双向链表实现,适合频繁插入删除操作,可作为栈或队列使用
- Vector是线程安全的List实现,但性能较低,现在较少使用
- 选择List实现类时要考虑操作类型、性能要求和线程安全需求
- 合理使用List的各种方法,注意避免常见的陷阱和性能问题
- 在实际开发中,ArrayList是首选,特殊场景下考虑其他实现
导航链接 上一章:集合框架概述 章节测试 下一章:Set接口详解 JavaScript