List接口概述
List是Java集合框架中有序、可重复元素的集合,提供精确的位置控制
核心特征
List接口继承自Collection接口,具有以下核心特性:
有序集合
List中的元素具有明确的顺序,可通过索引访问任意位置的元素
允许重复元素
List中可以包含重复的元素,这与Set集合不同
索引操作
提供基于索引的get、set、add、remove等操作方法
LinkedList
节点A
节点B
节点C
双向链表实现
Vector
元素1
元素2
元素3
动态数组实现
Stack
栈顶元素
中间元素
栈底元素
后进先出(LIFO)
LinkedList详解
双向链表实现的List,支持高效头尾操作
核心特性
- 基于双向链表实现,每个节点包含前驱和后继指针
- 在列表头尾的操作性能高,时间复杂度O(1)
- 任意位置插入/删除时间复杂度O(n)
- 实现了List和Deque接口,可用作列表、栈或队列
1
创建与基本操作
import java.util.LinkedList;
import java.util.List;
// 创建LinkedList
List<String> linkedList = new LinkedList<>();
// 添加元素 - 尾部添加
linkedList.add("Java");
linkedList.add("Python");
// 在指定位置插入元素
linkedList.add(1, "C++"); // [Java, C++, Python]
// 获取指定位置元素
String lang = linkedList.get(0); // "Java"
// 删除指定位置元素
linkedList.remove(2); // 删除"Python"
2
特殊操作(实现Deque接口)
// 创建LinkedList作为双端队列
LinkedList<String> deque = new LinkedList<>();
// 头部操作
deque.addFirst("First"); // 或 offerFirst()
deque.removeFirst(); // 或 pollFirst()
// 尾部操作
deque.addLast("Last"); // 或 offerLast()
deque.removeLast(); // 或 pollLast()
// 获取但不移除元素
String first = deque.peekFirst();
String last = deque.peekLast();
// 作为堆栈使用
deque.push("StackItem"); // 相当于addFirst
String top = deque.pop(); // 相当于removeFirst
使用场景
LinkedList在以下场景中有优势:
- 需要频繁在列表头尾进行添加/删除操作
- 需要将集合用作双端队列或堆栈
- 元素数量不确定且需要高效插入
- 不需要随机访问或随机访问频率较低
Vector详解
线程安全的动态数组,Java早期集合类
核心特性
- 基于动态数组实现,类似ArrayList但线程安全
- 默认容量为10,增长因子为100%(默认)
- 通过synchronized方法实现线程安全
- 提供了遍历集合的Enumeration接口
1
创建与基本操作
import java.util.Vector;
import java.util.Enumeration;
// 创建Vector并指定初始容量和增长因子
Vector<String> vector = new Vector<>(20, 5);
// 添加元素
vector.add("Element 1");
vector.addElement("Element 2"); // 历史遗留方法
// 插入元素到指定位置
vector.add(1, "New Element");
// 获取元素
String elem = vector.get(0);
String elemOld = vector.elementAt(0); // 历史方法
// 遍历 - 使用Enumeration
Enumeration<String> en = vector.elements();
while (en.hasMoreElements()) {
System.out.println(en.nextElement());
}
2
线程安全与替代方案
// Vector是线程安全的,但考虑以下替代方案:
// 1. Collections.synchronizedList
List<String> syncedList =
Collections.synchronizedList(new ArrayList<>());
// 2. CopyOnWriteArrayList (适合读多写少)
import java.util.concurrent.CopyOnWriteArrayList;
List<String> copyOnWriteList = new CopyOnWriteArrayList<>();
// 多线程环境下Vector的使用
Vector<Integer> safeVector = new Vector<>();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
safeVector.add(i);
}
};
// 创建多个线程访问Vector
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
遗留类注意事项
Vector是Java 1.0的遗留类,虽然提供线程安全,但同步粒度较粗可能影响性能。在Java 5+中,考虑使用并发集合类如CopyOnWriteArrayList或Collections.synchronizedList()包装的ArrayList替代。
Stack详解
后进先出(LIFO)的堆栈实现,继承自Vector
核心特性
- 继承自Vector类,线程安全
- 后进先出(LIFO)结构,只允许在栈顶操作
- 提供push、pop、peek等标准堆栈操作
- 不建议使用,已标记为遗留类
1
基本操作
import java.util.Stack;
// 创建Stack
Stack<String> stack = new Stack<>();
// 压栈操作
stack.push("First");
stack.push("Second");
stack.push("Third");
// 查看栈顶元素
String top = stack.peek(); // "Third"
// 出栈操作
String element = stack.pop(); // "Third"
// 检查是否为空
boolean isEmpty = stack.empty();
// 查找元素位置
int pos = stack.search("First"); // 1 (从栈顶开始)
2
现代替代方案
// 1. 使用ArrayDeque作为堆栈 (推荐)
import java.util.ArrayDeque;
import java.util.Deque;
Deque<String> dequeStack = new ArrayDeque<>();
// 压栈
dequeStack.push("First");
dequeStack.push("Second");
// 查看栈顶
String topElement = dequeStack.peek();
// 出栈
String popped = dequeStack.pop();
// 2. 使用LinkedList作为堆栈
Deque<String> linkedStack = new LinkedList<>();
linkedStack.push("Item1");
// 3. 使用Collections API创建同步堆栈
Deque<String> syncedStack =
Collections.synchronizedDeque(new ArrayDeque<>());
Stack类的使用警告
Stack类从Java 1.0开始存在,由于设计问题已被标记为遗留类(legacy class):
- 继承自Vector暴露了过多非堆栈操作方法(如insertElementAt)
- 性能较差,同步操作在单线程环境是负担
- 在Java 6之后,推荐使用Deque接口的实现类代替Stack
- 新代码应优先使用ArrayDeque
LinkedList、Vector与Stack对比
全面比较三种集合的实现机制、性能差异与适用场景
特性 | LinkedList | Vector | Stack |
---|---|---|---|
实现方式 | 双向链表 | 动态数组 | 继承自Vector |
线程安全 | 否 | 是(通过synchronized) | 是(继承Vector) |
效率特点 | 头尾操作O(1),随机访问O(n) | 随机访问O(1),插入删除O(n) | 仅栈顶操作O(1) |
继承关系 | 实现List和Deque | 实现List | 继承Vector |
空值处理 | 允许null元素 | 允许null元素 | 允许null元素 |
现代替代品 | 无,仍是主流实现 | Collections.synchronizedList CopyOnWriteArrayList |
ArrayDeque |
适用场景 | 双端操作、队列、栈 低随机访问频率 |
遗留系统维护 简单线程安全需求 |
基本不使用 |
添加操作
LinkedList: addFirst/addLast O(1)
Vector: add O(1) 均摊, 扩容时O(n)
Stack: push O(1) 均摊
删除操作
LinkedList: removeFirst/removeLast O(1)
Vector: remove O(n)
Stack: pop O(1)
访问操作
LinkedList: get O(n)
Vector: get O(1)
Stack: peek O(1)
常见错误与最佳实践
避免集合使用中的陷阱,掌握高效正确使用方法
常见错误
- 误用Vector的线程安全特性:跨多个方法组合操作仍需额外同步
- 在LinkedList中进行大量随机访问操作
- 在多线程环境下直接使用LinkedList
- 在新项目中使用Stack类
- 没有考虑Vector扩容导致的性能问题
- 对LinkedList使用索引遍历而非迭代器
最佳实践
- LinkedList适合频繁头尾操作和插入删除的场景
- 使用ArrayDeque代替Stack实现LIFO结构
- 在单线程环境下优先使用ArrayList而非Vector
- 对LinkedList使用Iterator进行遍历而非索引
- 使用Collections.synchronizedList替代Vector
- 多线程场景考虑CopyOnWriteArrayList
动手练习
- 使用LinkedList实现LRU缓存淘汰算法
- 用ArrayDeque实现逆波兰表达式计算器
- 比较LinkedList和ArrayList在10万次头部插入的性能差异
- 使用Vector和CopyOnWriteArrayList实现线程安全的计数器
- 使用栈结构解决括号匹配问题