在 Java 集合框架中LinkedList是 List 接口与 Deque 接口的双实现类底层基于双向链表实现凭借高效的插入、删除特性成为 ArrayList 的核心互补集合。一、LinkedList 基础定义LinkedList 是java.util包下的双向链表实现类同时实现了List和Deque双端队列接口既具备 List 的有序存储特性又拥有队列、双端队列、栈的功能特性。核心特性双向链表结构每个节点存储数据、前驱节点、后继节点内存非连续存储有序可重复元素存储顺序与插入顺序一致允许存储 null 值和重复元素无固定容量无需扩容节点动态创建理论容量无上限非线程安全多线程并发修改会引发数据异常随机访问低效不支持通过索引直接访问查找元素需遍历链表。二、LinkedList 的继承与实现关系LinkedList 的类定义源码清晰展示了其完整继承体系这是理解其功能的基础public class LinkedListE extends AbstractSequentialListE implements ListE, DequeE, Cloneable, java.io.Serializable核心继承 / 实现关系解析继承AbstractSequentialList抽象父类专为顺序访问的集合设计如链表实现了基于迭代器的通用方法与 ArrayList 继承的AbstractList形成区分实现List接口遵循列表规范提供增删改查、索引操作等核心功能实现Deque接口核心特性具备双端队列能力支持头 / 尾快速增删元素可作为栈、队列、双端队列使用实现Cloneable接口支持浅克隆实现Serializable接口支持序列化可网络传输与持久化。关键区别ArrayList 继承AbstractList支持随机访问LinkedList 继承AbstractSequentialList仅支持顺序访问。三、LinkedList 源码解析LinkedList 的核心是双向链表节点设计、头尾节点管理、节点操作逻辑无扩容机制源码比 ArrayList 更简洁易懂。1. 核心成员变量public class LinkedListE extends AbstractSequentialListE implements ListE, DequeE, Cloneable, java.io.Serializable { // 链表元素个数 transient int size 0; /** * 链表头节点第一个节点 */ transient NodeE first; /** * 链表尾节点最后一个节点 */ transient NodeE last; // 序列化版本号 private static final long serialVersionUID 876323262645176354L; }2. 核心内部类Node双向链表节点LinkedList 的存储单元是Node 节点这是双向链表的核心源码如下private static class NodeE { // 存储的元素数据 E item; // 后继节点指向后一个元素 NodeE next; // 前驱节点指向前一个元素 NodeE prev; // 节点构造方法传入前驱、数据、后继完成节点关联 Node(NodeE prev, E element, NodeE next) { this.item element; this.next next; this.prev prev; } }节点结构图解prev节点 ← [item, prev, next] → next节点每个节点都能找到前后节点这是双向链表的核心优势。3. 构造方法LinkedList 提供两个极简构造方法无容量参数无需扩容/** * 无参构造创建空链表头尾节点均为null */ public LinkedList() { } /** * 集合参数构造将指定集合元素添加到链表中 */ public LinkedList(Collection? extends E c) { this(); addAll(c); }对比ArrayList 无参构造会初始化空数组LinkedList 无参构造直接为空链表无任何内存分配。4. 核心节点操作工具方法LinkedList 所有增删改查底层都是头节点、尾节点、中间节点的关联操作核心封装了 4 个工具方法1linkFirst将元素添加到链表头部private void linkFirst(E e) { // 暂存原头节点 final NodeE f first; // 创建新节点前驱为null数据为e后继为原头节点 final NodeE newNode new Node(null, e, f); // 新节点成为新头节点 first newNode; // 如果原链表为空新节点也是尾节点 if (f null) last newNode; else // 原头节点的前驱指向新节点 f.prev newNode; size; modCount; }2linkLast将元素添加到链表尾部默认 add 方法调用void linkLast(E e) { // 暂存原尾节点 final NodeE l last; // 创建新节点前驱为原尾节点数据为e后继为null final NodeE newNode new Node(l, e, null); // 新节点成为新尾节点 last newNode; // 如果原链表为空新节点也是头节点 if (l null) first newNode; else // 原尾节点的后继指向新节点 l.next newNode; size; modCount; }3linkBefore在指定节点前插入元素中间插入void linkBefore(E e, NodeE succ) { // 获取指定节点的前驱节点 final NodeE pred succ.prev; // 创建新节点前驱pred后继succ final NodeE newNode new Node(pred, e, succ); // 指定节点的前驱指向新节点 succ.prev newNode; // 如果前驱为null新节点为头节点 if (pred null) first newNode; else pred.next newNode; size; modCount; }4unlink删除指定节点核心删除方法E unlink(NodeE x) { final E element x.item; final NodeE next x.next; final NodeE prev x.prev; // 如果是头节点删除后后继节点成为新头节点 if (prev null) { first next; } else { prev.next next; x.prev null; // 断开前驱引用帮助GC } // 如果是尾节点删除后前驱节点成为新尾节点 if (next null) { last prev; } else { next.prev prev; x.next null; // 断开后继引用帮助GC } x.item null; // 数据置空 size--; modCount; return element; }四、LinkedList 核心方法源码解析基于上述节点工具方法LinkedList 实现了 List 和 Deque 的所有核心方法逻辑高度统一。1. add () 添加元素最常用// 默认添加到尾部 public boolean add(E e) { linkLast(e); return true; } // 指定索引位置添加 public void add(int index, E element) { checkPositionIndex(index); // 如果是尾部直接调用linkLast if (index size) linkLast(element); else // 中间插入找到index对应节点调用linkBefore linkBefore(element, node(index)); }2. node () 查找指定索引的节点随机访问低效根源NodeE node(int index) { // 二分优化判断index在前半段还是后半段减少遍历次数 if (index (size 1)) { // 前半段从头节点向后遍历 NodeE x first; for (int i 0; i index; i) x x.next; return x; } else { // 后半段从尾节点向前遍历 NodeE x last; for (int i size - 1; i index; i--) x x.prev; return x; } }优化点JDK 做了二分遍历优化但时间复杂度仍为 O (n)远慢于 ArrayList 的 O (1)。3. get () 获取元素public E get(int index) { checkElementIndex(index); // 调用node方法遍历查找节点返回数据 return node(index).item; }4. remove () 删除元素// 根据索引删除 public E remove(int index) { checkElementIndex(index); return unlink(node(index)); } // 根据元素删除 public boolean remove(Object o) { if (o null) { // 遍历链表删除null元素 for (NodeE x first; x ! null; x x.next) { if (x.item null) { unlink(x); return true; } } } else { // 遍历链表删除指定元素 for (NodeE x first; x ! null; x x.next) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; }5. Deque 接口方法栈 / 队列专用LinkedList 可直接作为栈、队列使用无需额外实现// 入队/入栈 public void push(E e) { addFirst(e); } // 出队/出栈 public E pop() { return removeFirst(); } // 获取队头/栈顶元素 public E peek() { return (first null) ? null : first.item; }五、LinkedList 迭代器原理LinkedList 没有实现RandomAccess接口只能使用迭代器 / 增强 for 循环遍历普通 for 循环效率极低迭代器基于双向链表顺序访问实现。1. 核心迭代器源码ListItrprivate class ListItr implements ListIteratorE { // 上一个返回的节点 private NodeE lastReturned; // 下一个要遍历的节点 private NodeE next; // 下一个节点索引 private int nextIndex; // 快速失败标记 private int expectedModCount modCount; // 判断是否有下一个元素 public boolean hasNext() { return nextIndex size; } // 获取下一个元素顺序遍历 public E next() { checkForComodification(); lastReturned next; next next.next; nextIndex; return lastReturned.item; } }2. 快速失败机制Fail-Fast与 ArrayList 完全一致modCount链表修改次数增 / 删都会 1迭代器初始化时会拷贝modCount为expectedModCount迭代过程中如果链表被外部修改两个值不相等立即抛出ConcurrentModificationException。3. 遍历建议禁止使用普通 for 循环每次 get (index) 都会从头遍历链表效率极差优先使用迭代器 / 增强 for 循环顺序遍历时间复杂度 O (n)性能最优。六、LinkedList 与 ArrayList 对比两者底层结构、性能、适用场景完全互补对比维度ArrayListLinkedList底层结构动态 Object 数组内存连续双向链表内存非连续随机访问支持O (1) 时间复杂度效率极高不支持O (n) 时间复杂度效率低插入 / 删除末尾操作 O (1)中间操作 O (n)需移动元素头 / 尾操作 O (1)中间操作 O (n)仅修改引用扩容机制1.5 倍动态扩容需数组复制无扩容节点动态创建内存占用内存紧凑扩容会产生空闲空间每个节点存储数据 前后指针内存开销更大遍历方式普通 for / 迭代器均可仅推荐迭代器 / 增强 for 循环继承父类AbstractList支持随机访问AbstractSequentialList顺序访问实现接口List、RandomAccessList、Deque双端队列线程安全非线程安全非线程安全适用场景大量查询、读取操作大量头 / 尾插入、删除操作总结读多写少、频繁随机访问 →ArrayList开发首选频繁头尾增删、作为栈 / 队列使用 →LinkedList两者均非线程安全多线程环境使用CopyOnWriteArrayList。七、LinkedList 面试高频考点1. LinkedList 的底层结构是什么基于双向链表实现每个节点包含item数据、prev前驱节点、next后继节点。2. LinkedList 为什么不需要扩容链表无固定容量新增元素时动态创建 Node 节点通过引用关联无需像数组一样重新分配内存。3. LinkedList 插入 / 删除为什么比 ArrayList 快ArrayList中间插入 / 删除需要移动后续所有元素时间复杂度 O (n)LinkedList仅需修改节点的前驱 / 后继引用无需移动元素头 / 尾操作时间复杂度 O (1)。4. LinkedList 为什么随机访问效率低不支持索引直接访问查找元素需要从头 / 尾遍历链表即使 JDK 做了二分优化时间复杂度仍为 O (n)。5. LinkedList 可以作为哪些数据结构使用同时实现了 Deque 接口可作为List列表、栈Stack、队列Queue、双端队列Deque。6. LinkedList 和 ArrayList 的核心区别核心区别是底层结构数组 vs 双向链表由此衍生出访问效率、增删效率、内存占用、适用场景的全部差异。7. LinkedList 遍历为什么不推荐用普通 for 循环普通 for 循环每次调用get(index)都会重新遍历链表时间复杂度 O (n²)性能极差。8. LinkedList 是线程安全的吗如何保证安全非线程安全多线程环境可使用Collections.synchronizedList包装或使用 JUC 包的ConcurrentLinkedQueue并发链表。八、总结LinkedList 是基于双向链表设计的多功能集合凭借无扩容、头尾操作高效、支持栈 / 队列特性成为 ArrayList 的完美互补。核心记忆点底层双向链表无扩容节点动态创建优势头尾增删极快支持多种数据结构劣势随机访问低效内存开销大场景频繁头尾操作、栈 / 队列需求。