20260731-笔记.md 10 KB

20260731 课堂笔记 — LinkedList 多接口形态 / Iterator 迭代器

  • 日期:2026-07-31
  • 项目:c260731
  • 包路径:course
  • 作者:WanJL

目录

  1. LinkedList 多接口形态(List / Queue / Deque)
  2. Iterator 迭代器
  3. Collection 体系回顾:Iterable → Collection
  4. 随堂练习要点
  5. 拓展阅读

1. LinkedList 多接口形态(List / Queue / Deque)

概念

LinkedList 是 Java 集合框架中功能最「全面」的实现类之一,它同时实现了多个接口:

  • List<E> 接口 —— 列表(线性表),有序、可重复、带索引
  • Queue<E> 接口 —— 队列,先进先出(FIFO)
  • Deque<E> 接口 —— 双端队列(Double Queue),两端都可以入队 / 出队

同一个 LinkedList 对象,可以用不同的接口类型去引用。声明类型不同,「看得见」的方法就不同——这是接口多态(编译看左边:接口类型决定可用方法;运行看右边:真实对象是 LinkedList)。

声明类型 语义 可见的核心方法
LinkedList<Object> 最全的方法集合(链表本体) 链表 + List + Queue + Deque 全部方法
List<Object> 列表线性表 add/get/set/remove、indexOf、contains 等
Queue<Object> 队列(FIFO) offer 入队、poll 出队、peek 查看队头
Deque<Object> 双端队列 addFirst/addLast、pollFirst/pollLast、peekFirst/peekLast、push/pop(栈)

代码示例

// 来源:course/Demo01.java
package course;

import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class Demo01 {
    public static void main(String[] args) {
        // 使用最全的方法 --- 链表
        LinkedList<Object> list = new LinkedList<>();
        // 如果想使用 List 的方法 --- 列表线性表
        List<Object> list1 = new LinkedList<>();
        // 如果想使用队列 --- Queue
        Queue<Object> queue = new LinkedList<>();
        // 如果想使用双端队列 --- Double Queue
        Deque<Object> deque = new LinkedList<>();
    }
}

关键理解

  1. 一个对象,多种身份:new LinkedList<>() 创建的是同一个对象,但可以赋予 List、Queue、Deque 三种「身份」。
  2. 接口作为引用类型 = 能力限定:用 Queue 引用时只能调用队列方法(如 offer/poll/peek),无法调用 get(int) 这类 List 方法——把能力「收窄」到所需范围。
  3. 实际应用:需要栈/队列场景时,用 Queue/Deque 引用 LinkedList,语义更清晰,也方便后续替换实现类。

2. Iterator 迭代器

概念

由于 Collection 集合接口继承了 Iterable 接口,所以我们使用的所有单列集合都具备 Iterable 的方法(iterator()),并且各个实现类都重写了它。

  • 通过集合对象的 iterator() 方法获取该集合对应的迭代器对象(Iterator<E>)
  • 迭代器提供统一的遍历方式,与集合的内部结构(数组 / 链表)无关
  • 特别适合遍历没有索引的集合(如 Set、LinkedList)

Iterator 核心方法

方法 返回值 说明
boolean hasNext() boolean 判断迭代器是否还有下一个元素
E next() E 返回下一个元素,并把指针向后移动一位
void remove() void 从集合中移除上次 next() 返回的元素(可选操作)

迭代器内部有一个指针,初始位置在第一个元素之前:

 [元素1] → [元素2] → [元素3] → [元素4]  …  → null
   ↑
 iterator 初始位置(第一个元素之前)
  • hasNext():判断指针后是否还有元素
  • next():取出当前元素并把指针后移

代码示例

// 来源:course/Demo02.java
package course;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

public class Demo02 {
    /*
        由于Collection集合接口继承了Iterable接口
        所以我们使用的所有的单列集合,都具有Iterable的方法,并且重写了方法
     */
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("元素1");
        list.add("元素2");
        // ... 共添加10个元素

        // 方式一:我们遍历集合 —— for + 索引(ArrayList 有索引才支持)
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        // 方式二:通过迭代器进行迭代遍历
        Iterator<String> iterator = list.iterator();   // 通过集合对象获取它对应的迭代器对象
        while (iterator.hasNext()) {                   // 判断迭代器有没有下一个元素,有就继续
            String element = iterator.next();          // 通过迭代器对象获取下一个元素
            System.out.println(element);
        }

        // 创建字符串泛型的 LinkedList 集合
        LinkedList<String> list1 = new LinkedList<>();
        // 添加10个元素 ...

        // LinkedList 同样可以使用迭代器(链表没有索引,for+get 效率低)
        Iterator<String> iterator1 = list1.iterator();
        while (iterator1.hasNext()) {
            String s = iterator1.next();
            System.out.println(s);
        }
    }
}

迭代器使用模板

Iterator<E> it = 集合对象.iterator();  // 1. 获取迭代器
while (it.hasNext()) {                 // 2. 判断是否有下一个
    E e = it.next();                   // 3. 获取下一个元素并后移指针
    // 处理元素
}

注意

  • 指针只能单向移动:next() 只能向后,不能回退。
  • next() 会移动指针,多次调用 next() 会跳过元素。
  • 迭代过程中若集合被修改(add/remove),会抛出 ConcurrentModificationException(快速失败机制)。

3. Collection 体系回顾:Iterable → Collection

继承结构

Iterable<E>                        —— 根接口,定义了 iterator()
    │
Collection<E>                      —— 单列集合根接口(继承 Iterable)
    ├── List<E>                    —— 列表:有序、可重复、带索引
    │      ├── ArrayList<E>        —— 数组结构,随机访问快
    │      └── LinkedList<E>       —— 双链表结构,插入删除快
    ├── Queue<E>                   —— 队列:先进先出(FIFO)
    │      └── Deque<E>            —— 双端队列(LinkedList 实现)
    └── Set<E>                     —— 集合:不可重复

LinkedList 与多个接口的关系

                 LinkedList<E>
                      │
        ┌─────────────┼─────────────┐
        ▼             ▼             ▼
      List<E>      Queue<E>      Deque<E>
      (线性表)   (队列FIFO)  (双端队列/栈)

所以代码中才能写出:

List<Object> list1 = new LinkedList<>();
Queue<Object> queue = new LinkedList<>();
Deque<Object> deque = new LinkedList<>();

遍历集合的三种方式对比

方式 适用场景 示例
for + size() + get(i) 有索引的 List(ArrayList 效率高) for (int i = 0; i < list.size(); i++)
Iterator 迭代器 所有单列集合(通用方式) while (it.hasNext()) { it.next(); }
增强 for(foreach) 所有集合与数组(底层也是迭代器) for (String s : list)

4. 随堂练习要点

练习一:LinkedList 多接口引用

核心步骤:

  1. 创建 LinkedList<Object> 对象
  2. 分别用 LinkedList、List、Queue、Deque 四种类型引用它
  3. 体会「声明类型不同 → 可见方法不同」的接口多态

思考:

  • 用 Queue 引用时,能否调用 get(int)?—— 不能,编译错误,Queue 接口中没有该方法
  • 为什么说 LinkedList 既能当队列又能当栈?—— 它实现了 Deque,Deque 提供了 push/pop(栈)和 addFirst/addLast(双端队列)

练习二:Iterator 迭代器遍历

核心步骤:

  1. 创建一个 ArrayList<String>,添加 10 个元素
  2. 用 for + get(i) 遍历
  3. 用 iterator() 获取迭代器,while (hasNext()) + next() 遍历
  4. 再对 LinkedList<String> 执行同样的迭代器遍历

思考:

  1. hasNext() 和 next() 分别做什么?—— 判断是否存在下一个元素 / 取出下一个元素并移动指针
  2. 为什么 LinkedList 用 for + get(i) 效率低?—— 每次 get(i) 都要从头遍历节点,时间复杂度 O(n),而迭代器沿链表逐个移动只需 O(1)
  3. 增强 for 的底层机制是什么?—— 编译器会把 foreach 翻译成迭代器遍历

5. 拓展阅读

官方文档

推荐阅读

  • 《Java 核心技术 卷 I》第 9 章 集合 —— 迭代器与 foreach 的关系
  • 《Effective Java》第 3 版 第 58 条:优先使用 foreach 循环而非传统 for 循环

相关知识点

前置知识 当前知识 后续知识
ArrayList 底层原理(0729) LinkedList 多接口形态(List/Queue/Deque) ListIterator(双向迭代)
LinkedList 双链表理论(0730) Iterator 迭代器 增强 for / forEach 方法
泛型与集合体系(0729) Iterable → Collection 继承体系 Set 集合与 Map 迭代