List
接口 是 Java 集合框架中用于存储有序集合的接口,它继承自 Collection
接口。List
能够存储重复的元素,并且每个元素都有对应的整数索引,索引用于标识元素在集合中的位置。常见的实现类有 ArrayList、LinkedList、Vector、Stack,不过 Stack 已经不推荐使用了,应该用 Deque 代替。
ArrayList
ArrayList 和 TypeScript 中的数组比较接近,长度可以变化,支持使用 index 随机访问;容量不够时会自动扩容,默认初始容量为 10,扩容时按 1.5 倍增长。在数据量大、长度频繁变化场景效率较低
List<String> list = new ArrayList<String>();
list.add("一");
list.add("二");
list.add("三");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
list.set(0, "1");
list.remove(1);
for (String s : list) {
System.out.println(s);
}
如果 ArrayList 中的元素是经过排序的,就可以使用二分查找法,效率更快
List<String> list = new ArrayList<String>();
list.add("a");
list.add("c");
list.add("b");
list.add("d");
Collections.sort(list);
System.out.println(list); // [a, b, c, d]
int index = Collections.binarySearch(list, "b");
System.out.println(index); // 1
LinkedList
LinkedList 是 List 和 Deque 接口的双向链表实现,提供了高效的插入和删除操作。相比于 ArrayList,LinkedList 在列表中间位置插入或删除元素时更高效,但随机访问速度较慢
- 只支持顺序访问,任意位置插入、删除效率较高
- 需要存储前后节点的引用,占用空间比 ArrayList 多
List<String> list = new LinkedList<String>();
list.add("一");
list.add("二");
list.add("三");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
list.set(0, "1");
list.remove(1);
for (String s : list) {
System.out.println(s);
}
LinkedList 还有几个常用方法,在队列、栈等数据结构中非常有用
- getFirst():获取第一个元素
- getLast():获取最后一个元素
- removeFirst():删除第一个元素
- removeLast():删除最后一个元素
- poll()/pollFirst():删除并返回第一个元素
- pollLast():删除并返回最后一个元素
- peekFirst():返回但不删除第一个元素
- peekLast():返回但不删除最后一个元素
- push():在头部插入元素,相当于 addFirst()
- pop():删除头部元素,等价于 removeFirst()
ArrayList 与 LinkedList 的比较
ArrayList 和 LinkedList 是 List 接口最常用的两种实现类,它们在内部数据结构、性能特性和适用场景上各有不同。
- ArrayList:基于动态数组实现,底层使用数组存储元素
- LinkedList:基于双向链表实现,每个元素都是一个节点,包含前后节点的引用
操作 | ArrayList | LinkedList |
---|---|---|
随机访问 | O(1) | O(n) |
插入/删除 | O(n) | O(1)(在已知位置) |
添加到末尾 | O(1) | O(1) |
Vector 与 Stack
Vector 和 Stack 虽然作为早期的集合类具有一定的历史意义,但由于其设计上的局限性和性能开销,在现代 Java 编程中已经逐渐被更高效、更灵活的集合类所取代。开发者应优先选择 ArrayList 替代 Vector,以及 Deque 的实现类(如 ArrayDeque)替代 Stack,以编写出更简洁、高效且可维护的代码
使用 ArrayList 替代 Vector
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ArrayListInsteadOfVector {
public static void main(String[] args) {
// 创建一个非线程安全的 ArrayList
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
System.out.println("ArrayList: " + list);
// 输出: ArrayList: [Java, Python, C++]
// 如果需要线程安全,可以使用 synchronizedList
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
synchronizedList.add("Java");
synchronizedList.add("Python");
synchronizedList.add("C++");
System.out.println("同步后的 ArrayList: " + synchronizedList);
// 输出: 同步后的 ArrayList: [Java, Python, C++]
}
}
使用 Deque 替代 Stack
Deque(双端队列)接口继承自 Queue,允许在两端插入和移除元素。Deque 的实现类如 ArrayDeque 和 LinkedList 提供了比 Stack 更为灵活和高效的堆栈和队列操作
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeInsteadOfStack {
public static void main(String[] args) {
// 使用 Deque 实现堆栈操作
Deque<Integer> stack = new ArrayDeque<>();
// 压栈
stack.push(10);
stack.push(20);
stack.push(30);
System.out.println("Deque Stack: " + stack);
// 输出: Deque Stack: [30, 20, 10]
// 弹栈
int popped = stack.pop();
System.out.println("弹出的元素: " + popped); // 输出: 弹出的元素: 30
System.out.println("弹栈后 Deque: " + stack);
// 输出: 弹栈后 Deque: [20, 10]
// 查看栈顶元素
int peek = stack.peek();
System.out.println("栈顶元素: " + peek); // 输出: 栈顶元素: 20
}
}