在 Java 中,List 是 Collection 接口的子接口,用于存储有序、可重复的元素集合。List 提供了通过索引访问元素的能力,并允许插入重复元素,是开发中最常用的集合类型之一。
List 接口的核心特性
有序性:元素按照插入顺序排列,可通过索引访问(如 get(0))。
可重复性:允许存储重复的元素。
索引支持:提供基于索引的操作(如 add(index, element)、remove(index))。
常用实现类:
ArrayList:基于动态数组实现,支持随机访问,插入 / 删除效率较低。
LinkedList:基于双向链表实现,插入 / 删除效率高,随机访问效率较低。
Vector:线程安全的动态数组(已过时,推荐使用 Collections.synchronizedList 或 CopyOnWriteArrayList)。
List 的基本操作
以下是 List 的常用方法示例:
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// 创建 ArrayList
List<String> fruits = new ArrayList<>();
// 添加元素
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
fruits.add(1, "Blueberry"); // 在索引 1 处插入元素
// 访问元素
System.out.println("第一个元素: " + fruits.get(0)); // Apple
System.out.println("列表大小: " + fruits.size()); // 4
// 修改元素
fruits.set(2, "Blackberry"); // 将索引 2 的元素替换为 Blackberry
// 删除元素
fruits.remove(3); // 删除索引 3 的元素(Cherry)
fruits.remove("Apple"); // 删除值为 "Apple" 的元素
// 判断元素是否存在
System.out.println("是否包含 Banana: " + fruits.contains("Banana")); // true
// 遍历列表
System.out.println("遍历方式一(for-each):");
for (String fruit : fruits) {
System.out.println(fruit);
}
System.out.println("遍历方式二(迭代器):");
var iterator = fruits.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("遍历方式三(forEach + Lambda):");
fruits.forEach(fruit -> System.out.println(fruit));
}
}
ArrayList vs. LinkedList
特性 ArrayList LinkedList
底层结构 动态数组 双向链表
随机访问效率 高(O (1)) 低(O (n))
插入 / 删除效率 尾部插入快,中间插入慢 任意位置插入快(O (1))
内存占用 连续内存,可能存在空间浪费 非连续内存,每个节点需额外指针
LinkedList 的特有方法
LinkedList 实现了 Deque 接口,提供了队列和栈的操作方法:
import java.util.LinkedList;
public class LinkedListExample {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
// 添加元素(作为队列)
list.offer("A"); // 队尾添加
list.offerFirst("B"); // 队首添加
list.offerLast("C"); // 队尾添加
// 作为队列使用
System.out.println("队首元素: " + list.peek()); // B
System.out.println("出队元素: " + list.poll()); // B
System.out.println("新队首: " + list.peekFirst()); // A
// 作为栈使用
list.push("D"); // 栈顶压入
System.out.println("栈顶元素: " + list.peek()); // D
System.out.println("弹栈元素: " + list.pop()); // D
}
}
List 的排序与转换
使用 Collections.sort() 或 List.sort() 对列表排序:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ListSortingExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(3);
numbers.add(1);
numbers.add(2);
// 自然排序
Collections.sort(numbers);
System.out.println("自然排序: " + numbers); // [1, 2, 3]
// 自定义排序(降序)
numbers.sort(Comparator.reverseOrder());
System.out.println("降序排序: " + numbers); // [3, 2, 1]
// 列表转数组
Integer[] array = numbers.toArray(new Integer[0]);
System.out.println("数组: " + Arrays.toString(array));
// 数组转列表
List<String> fruits = Arrays.asList("Apple", "Banana", "Cherry");
System.out.println("列表: " + fruits);
}
}
常见面试问题
ArrayList 如何扩容?
初始容量为 10,扩容时新容量为原容量的 1.5 倍(oldCapacity + (oldCapacity >> 1))。
如何在遍历 List 时安全删除元素?
使用 Iterator 的 remove() 方法,避免 ConcurrentModificationException。
ArrayList 和 Vector 的区别?
Vector 线程安全(方法加 synchronized),ArrayList 非线程安全。
List 和 Set 的区别?
List 有序可重复,Set 无序不可重复。
掌握 List 的核心实现类(ArrayList 和 LinkedList)及其适用场景,是编写高效 Java 代码的基础。根据业务需求选择合适的实现类,可以显著提升程序性能。