--- title: "00-List总览" created: 2025-12-02 tags: - Java --- # List > [!note] 定位说明 > 本篇是 List 系列的总览:先建立"List 是什么、三实现怎么选"的整体认知,再进入各实现类详篇。动线:本篇 → [[01-ArrayList|ArrayList]] → [[02-LinkedList|LinkedList]] → [[03-Vector|Vector]]。 **Java 中的 List 接口:有序、可重复的集合框架核心** List 是 Java 集合框架中最常用的接口之一,继承自`Collection`,具有以下核心特性: - **有序性**:元素按插入顺序存储,支持通过索引(下标)访问元素。 - **可重复性**:允许存储重复元素。 - **丰富的操作接口**:提供`get(int index)`、`add(int index, E element)`、`remove(int index)`等基于索引的操作方法,方便数据的随机访问和位置调整。 ## 继承关系 ```mermaid graph TD Iterable["Iterable<E>"] --> Collection["Collection<E>"] Collection --> List["List<E>"] List --> ArrayList["ArrayList
动态数组"] List --> LinkedList["LinkedList
双向链表"] List --> Vector["Vector
同步动态数组(遗留)"] Vector --> Stack["Stack
栈(遗留)"] ``` 一句话记忆:**List = 可按下标操作的动态序列**。ArrayList 是默认选择,LinkedList 换来了头尾操作的高效,Vector 是历史遗留(见其篇内"为什么现在不用 Vector")。 List 接口有多个实现类:[[01-ArrayList|ArrayList]]、[[02-LinkedList|LinkedList]]、[[03-Vector|Vector]] | **维度** | **ArrayList** | **LinkedList** | **Vector** | | --- | --- | --- | --- | | **底层结构** | 动态数组(`Object[]`,连续内存) | 双向链表(`Node`节点,非连续内存) | 动态数组(`Object[]`,连续内存) | | **线程安全** | ❌ 非线程安全 | ❌ 非线程安全 | ✅ 线程安全(方法加 `synchronized`) | | **随机访问效率** | ✅ 快速(O (1),索引直接定位) | ❌ 低效(O (n),需遍历链表) | ✅ 快速(O (1),索引直接定位) | | **插入 / 删除效率** | ❌ 尾部 O (1)(若需扩容则 O (n)) 中间 O (n)(移动元素) | ✅ 头尾 O (1)(改指针) 中间 O (n)(遍历定位) | ❌ 尾部 O (1)(若需扩容则 O (n)) 中间 O (n)(移动元素) | | **扩容机制** | 自动扩容(默认初始 10,1.5 倍增长) | 无需扩容(链表天然动态) | 自动扩容(默认初始 10,**2 倍增长**) | | **内存开销** | 较小(数组紧凑存储,无额外指针) | 较大(每个节点需存储 `prev` 和 `next` 指针) | 较大(同步机制额外开销 + 数组存储) | | **Null 元素支持** | ✅ 可存储多个 `null` | ✅ 可存储多个 `null` | ✅ 可存储多个 `null` | | **适用场景** | 单线程、读多写少、随机访问频繁 (如缓存、索引表、数据库结果集) | 单线程、写多读少、频繁头尾操作 (如消息队列、栈 / 队列、链式数据结构) | 多线程、需要线程安全的随机访问场景 (如共享数据读写、旧系统兼容) | | **典型应用** | `for` 循环遍历、排行榜(需索引) | `Deque` 双端队列、LRU 缓存(头尾操作) | 多线程计数器、共享日志列表 | | **替代方案** | 多线程时用 `Collections.synchronizedList()` 或 `CopyOnWriteArrayList` | 多线程时用 `ConcurrentLinkedQueue` | 优先用 `ArrayList + 同步包装` 或 `CopyOnWriteArrayList` | ## 常用方法速查 ```java List list = new ArrayList<>(); list.add("b"); // 尾部追加 list.add(0, "a"); // 指定位置插入(后面的元素整体后移) list.set(0, "A"); // 覆盖指定位置元素,返回旧值 list.get(0); // 按下标取值 list.remove(0); // 按下标删(注意重载歧义,见下) list.remove("A"); // 按对象删(equals 判等) list.indexOf("A"); // 第一次出现的下标,没有返回 -1 list.contains("A"); // 是否包含(底层 indexOf) list.size(); // 元素个数 list.isEmpty(); // 是否为空 list.sort(Comparator.comparingInt(String::length)); // 就地排序 list.subList(0, 2); // 截取 [0,2) 视图——改视图会影响原 List list.clear(); // 清空 ``` > [!warning] `remove` 的重载歧义(高频面试坑) > `List list` 里调 `remove(1)` 删的是**下标 1**,不是元素 `1`——因为 `remove(int index)` 精确匹配优先于 `remove(Object o)`。要按元素删必须写 `list.remove(Integer.valueOf(1))`。 ## 遍历的四种方式 ```java List list = List.of("a", "b", "c"); // 1. 普通for——需要下标时用 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } // 2. 增强for——只读遍历的首选 for (String s : list) { System.out.println(s); } // 3. Iterator——遍历中要删元素时唯一安全的方式(fail-fast 见 ArrayList 篇) Iterator it = list.iterator(); while (it.hasNext()) { String s = it.next(); if ("a".equals(s)) it.remove(); // 用迭代器自己的 remove,不是 list.remove } // 4. ListIterator——List 独有,可双向遍历、可修改 ListIterator lit = list.listIterator(); while (lit.hasNext()) { String s = lit.next(); lit.set(s.toUpperCase()); // 边遍历边改 } while (lit.hasPrevious()) { // 此时光标在末尾,可反向再走一遍 System.out.println(lit.previous()); } ``` ## 创建 List 的三种姿势(面试高频) ```java // 1. new —— 可变,日常主力 List a = new ArrayList<>(); a.add("x"); // ✅ 可以增删改 // 2. Arrays.asList —— 定长视图 List b = Arrays.asList("x", "y"); // b.add("z"); // ❌ 抛 UnsupportedOperationException // 但 b.set(0, "z") 可以!—— 它是"长度固定的 List",不是不可变 // 3. List.of —— 真不可变(JDK 9+) List c = List.of("x", "y"); // c.add("z"); c.set(0, "z"); // ❌ 全部抛 UnsupportedOperationException ``` 三者本质区别:**能不能 add/remove** 和**能不能 set** 是两件事——`Arrays.asList` 定长但可改元素,`List.of` 连元素都不能改。另外 `List.of` 不允许 `null` 元素,前两者允许。 ## 与 equals/hashCode 的勾连 `contains`、`remove(Object)`、`indexOf` 判断"是不是同一个元素"靠的是 `equals()`,而 `HashSet`/`HashMap` 场景还依赖 `hashCode()`——自定义类放进集合前不重写这两个方法,就会出现"明明放进去却 contains 不到"的问题。详见 [[01-Object通用方法|Object 通用方法]]。 --- ⬅️ [[00-容器总览|00-容器总览]] 🏠 [[00-Java|00-Java]] ➡️ [[01-ArrayList|ArrayList]]