Java中的List实现类详解
List是Java集合框架中最常用的接口之一,表示有序的集合(也称为序列)。Java提供了多种List接口的实现,每种实现都有其特定的使用场景和性能特点。
1. 主要List实现类
ArrayList
- 底层实现:动态数组
- 特点:
- 随机访问速度快(O(1))
- 插入和删除元素较慢(除非在末尾操作)
- 非线程安全
- 扩容机制:默认初始容量10,扩容时增加50%(newCapacity = oldCapacity + (oldCapacity >> 1))
- 最佳用途:频繁随机访问,较少在中间位置插入/删除元素
List<String> arrayList = new ArrayList<>();
// 指定初始容量
List<String> arrayListWithCapacity = new ArrayList<>(100);
LinkedList
- 底层实现:双向链表
- 特点:
- 插入和删除元素快(O(1)如果知道位置)
- 随机访问慢(O(n))
- 实现了Deque接口,可以用作队列或栈
- 非线程安全
- 内存开销:比ArrayList大(每个元素需要额外的前后指针)
- 最佳用途:频繁在列表中间插入/删除元素,不需要频繁随机访问
List<String> linkedList = new LinkedList<>();
// 作为双端队列使用
Deque<String> deque = new LinkedList<>();
Vector
- 底层实现:动态数组(类似ArrayList)
- 特点:
- 线程安全(方法级别同步)
- 性能较差(由于同步开销)
- 扩容机制:默认扩容为原来的2倍
- 历史:Java早期版本,现在很少使用
- 替代方案:使用Collections.synchronizedList或CopyOnWriteArrayList
List<String> vector = new Vector<>();
Stack
- 底层实现:继承自Vector
- 特点:
- LIFO(后进先出)数据结构
- 线程安全(继承自Vector)
- 不推荐使用(设计上有问题)
- 替代方案:使用Deque接口的实现(如ArrayDeque)
Stack<String> stack = new Stack<>();
2. 线程安全List实现
CopyOnWriteArrayList
- 底层实现:写时复制数组
- 特点:
- 线程安全
- 读操作无锁,性能高
- 写操作会复制整个底层数组
- 迭代器不会抛出ConcurrentModificationException
- 最佳用途:读多写少的并发场景
List<String> cowList = new CopyOnWriteArrayList<>();
Collections.synchronizedList
- 特点:
- 将普通List包装为线程安全List
- 方法级别同步
- 迭代时需要手动同步
- 性能:比CopyOnWriteArrayList在写操作上更快,但并发读性能较差
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
3. Java 9+新增的不可变List
List.of()
- 特点:
- 创建不可变列表
- 不允许null元素
- 空间优化(比new ArrayList更节省内存)
- Java版本:9+
- 最佳用途:创建常量列表或测试数据
List<String> immutableList = List.of("a", "b", "c");
4. 性能比较
操作 | ArrayList | LinkedList | Vector | CopyOnWriteArrayList |
---|---|---|---|---|
get(index) | O(1) | O(n) | O(1) | O(1) |
add(element) | O(1)摊销 | O(1) | O(1) | O(n) |
add(index, elem) | O(n) | O(1) | O(n) | O(n) |
remove(index) | O(n) | O(1) | O(n) | O(n) |
内存占用 | 较小 | 较大 | 较小 | 写时复制开销大 |
线程安全 | 否 | 否 | 是 | 是 |
5. 选择指南
使用场景 | 推荐实现 |
---|---|
频繁随机访问 | ArrayList |
频繁在中间位置插入/删除 | LinkedList |
需要栈/队列功能 | LinkedList(实现Deque) |
线程安全需求 | CopyOnWriteArrayList |
遗留代码维护 | Vector/Stack |
小型不可变列表 | List.of() |
需要同步的列表 | Collections.synchronizedList |
6. 最佳实践
预分配ArrayList容量:如果知道大致大小,可减少扩容开销
List<String> list = new ArrayList<>(expectedSize);
避免在ArrayList中间插入:大量插入考虑使用LinkedList
并发环境选择:
- 读多写少:CopyOnWriteArrayList
- 写多:Collections.synchronizedList或手动同步
遍历方式选择:
// 随机访问列表(如ArrayList) for (int i = 0; i < list.size(); i++) { String item = list.get(i); } // 顺序访问列表(如LinkedList) for (String item : list) { // 使用迭代器内部实现 }
避免使用Stack类:用ArrayDeque代替
Deque<String> stack = new ArrayDeque<>(); stack.push("a"); String top = stack.pop();
不可变列表优势:
- 更安全
- 更节省内存
- 线程安全
- 适合作为常量或返回空列表
// 代替 Collections.emptyList() List<String> empty = List.of(); // 代替 Arrays.asList()创建的半可变列表 List<String> immutable = List.of("a", "b", "c");
理解这些List实现类的特点和适用场景,可以帮助你在开发中做出更合理的选择,从而编写出更高效、更健壮的代码。