LinkedList知识点

一、LinkedList 核心定义

LinkedList 是 Java 集合框架中 List 接口的双向链表实现 ,同时实现了 Deque 接口(支持双端队列操作),位于 java.util 包下;线程不安全,允许存储 null 值,元素按插入顺序排列。

二、底层原理

  1. 存储结构 :底层基于双向链表 实现,每个元素封装为 Node 节点,节点包含 3 个属性:

    java

    运行

    复制代码
    private static class Node<E> {
        E item;        // 元素值
        Node<E> next;  // 后继节点引用
        Node<E> prev;  // 前驱节点引用
        // 构造方法
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

    链表有 first(头节点)和 last(尾节点)指针,无需连续内存空间。

  2. 无扩容机制:链表节点按需创建,添加元素时仅需新建 Node 并调整指针指向,不存在数组扩容 / 拷贝的性能损耗。

三、核心特性

表格

特性 说明
随机访问 不支持高效随机访问(时间复杂度 O (n)),需从表头 / 表尾遍历到目标索引
增删效率 首尾增删:O (1)(仅调整指针);指定位置增删:O (n)(需先遍历找到节点)
线程安全 线程不安全,多线程场景需使用 Collections.synchronizedList()ConcurrentLinkedDeque
允许 null 值 可存储 null 元素(支持多个 null)
双端队列特性 实现 Deque 接口,可作为栈(push/pop)、队列(offer/poll)使用
内存占用 每个节点需存储前驱 / 后继指针,内存开销比 ArrayList 大

四、常用核心方法

java

运行

复制代码
// 1. 初始化
LinkedList<String> list = new LinkedList<>();
LinkedList<String> list2 = new LinkedList<>(Arrays.asList("a", "b"));

// 2. 核心增删(双向链表特性)
list.add("java"); // 尾部添加(O(1))
list.addFirst("python"); // 头部添加(O(1))
list.addLast("c++"); // 尾部添加(等同于add(),O(1))
list.add(2, "go"); // 指定索引添加(O(n),需先遍历找节点)

list.removeFirst(); // 头部删除(O(1))
list.removeLast(); // 尾部删除(O(1))
list.remove(1); // 按索引删除(O(n))
list.remove("java"); // 按元素删除(O(n),需遍历)

// 3. 双端队列/栈操作(Deque接口)
list.offer("mysql"); // 队列:尾部添加
list.poll(); // 队列:头部移除(无元素返回null)
list.push("redis"); // 栈:头部添加
list.pop(); // 栈:头部移除(无元素抛异常)

// 4. 查
String first = list.getFirst(); // 头部元素(O(1))
String last = list.getLast(); // 尾部元素(O(1))
String elem = list.get(1); // 指定索引(O(n),效率低)
int index = list.indexOf("go"); // 查找元素索引(O(n))

// 5. 遍历(推荐方式)
// 方式1:增强for循环(底层迭代器,适合链表)
for (String s : list) {
    System.out.println(s);
}
// 方式2:迭代器(支持遍历中删除)
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    if (s.equals("go")) {
        it.remove(); // 避免ConcurrentModificationException
    }
}
// 方式3:降序遍历(双向链表优势)
ListIterator<String> listIt = list.listIterator(list.size());
while (listIt.hasPrevious()) {
    System.out.println(listIt.previous());
}

五、面试高频考点

1. LinkedList vs ArrayList 核心对比(必背)

表格

维度 ArrayList LinkedList
底层结构 动态数组(Object []) 双向链表(Node 节点)
随机访问 O (1)(快,索引直接定位) O (n)(慢,需遍历)
增删效率 尾部 O (1),非尾部 O (n)(移动元素) 首尾 O (1),中间 O (n)(找节点)
内存占用 连续内存,有扩容冗余 非连续内存,节点含指针,开销大
适用场景 频繁查询、少量增删 频繁首尾增删、队列 / 栈场景
遍历效率 for 循环(随机访问)更快 迭代器 / 增强 for 更快
2. 易错点
  • 随机访问性能陷阱 :避免用 for (int i=0; i<size; i++) { list.get(i); } 遍历 LinkedList,每次 get(i) 都会从头遍历,时间复杂度退化到 O (n²);
  • 栈 / 队列使用场景:LinkedList 实现了 Deque 接口,是 Java 中栈(替代过时的 Stack 类)、队列的常用实现;
  • 遍历删除 :同 ArrayList,增强 for 循环中直接 list.remove() 会抛 ConcurrentModificationException,需用迭代器的 remove()
  • null 值处理 :允许存储多个 null,indexOf(null) 可正常查找 null 元素位置。
3. 扩展考点
  • LinkedList 没有 ensureCapacity()/trimToSize() 方法(无数组,无需扩容 / 缩容);
  • JDK 中 LinkedList 的节点是私有的静态内部类,外部无法直接访问;
  • 双向链表支持正向 / 反向遍历(ListIterator 的 hasPrevious()/previous()),这是数组结构不具备的优势。

六、使用场景

  • 适合频繁首尾增删的场景(如消息队列、任务栈);
  • 适合需要双向遍历的场景;
  • 不适合频繁随机查询的场景(优先用 ArrayList)。

总结

LinkedList 核心关键点:

  1. 底层是双向链表,无扩容机制,首尾增删 O (1)、随机访问 O (n),内存开销比 ArrayList 大;
  2. 实现 Deque 接口,可作为栈 / 队列使用,是这类场景的首选;
  3. 与 ArrayList 核心区别在底层结构,前者适合频繁增删,后者适合频繁查询。
相关推荐
跳跳鱼1 小时前
ThreadLocal 核心源码解析:属性、内部类与重要接口深度剖析
java
JamesYoung79711 小时前
第七部分 — 存储 数据建模与迁移提示
java·开发语言·数据结构
大志学java2 小时前
idea中切换分支后,项目目录不显示的问题
java·elasticsearch·intellij-idea
程序员敲代码吗2 小时前
进程与线程:操作系统中的核心组件
java·开发语言
Java面试题总结2 小时前
java面试题及答案(基础题122道)
java·开发语言·jvm·spring·spring cloud·golang·java-ee
jacsonchen2 小时前
【MySQL】环境变量配置
java
番茄去哪了2 小时前
黑马点评实战篇千字总结
java·分布式·面向对象编程
pupudawang2 小时前
Java进阶——IO 流
java·开发语言·python
逆境不可逃2 小时前
【从零入门23种设计模式19】行为型之观察者模式
java·开发语言·算法·观察者模式·leetcode·设计模式·动态规划