【死磕 Java 集合】— LinkedList源码分析
【死磕 Java 集合】— LinkedList源码分析
作者:彤哥
问题
(1)LinkedList只是一个List吗?
(2)LinkedList还有其它什么特性吗?
(3)LinkedList为啥经常拿出来跟ArrayList比较?
(4)我为什么把LinkedList放在最后一章来讲?
简介
LinkedList是一个以双向链表实现的List,它除了作为List使用,还可以作为队列或者栈来使用,它是怎么实现的呢?让我们一起来学习吧。
继承体系
通过继承体系,我们可以看到LinkedList不仅实现了List接口,还实现了Queue和Deque接口,所以它既能作为List使用,也能作为双端队列使用,当然也可以作为栈使用。
源码分析
主要属性
// 元素个数
transient int size = 0;
// 链表首节点
transient Node<E> first;
// 链表尾节点
transient Node<E> last;
属性很简单,定义了元素个数size和链表的首尾节点。
主要内部类
典型的双链表结构。
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;
}
}
主要构造方法
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
两个构造方法也很简单,可以看出是一个无界的队列。
添加元素
作为一个双端队列,添加元素主要有两种,一种是在队列尾部添加元素,一种是在队列首部添加元素,这两种形式在LinkedList中主要是通过下面两个方法来实现的。
// 从队列首添加元素
private void linkFirst(E e) {
// 首节点
final Node<E> f = first;
// 创建新节点,新节点的next是首节点
final Node<E> newNode = new Node<>(null, e, f);
// 让新节点作为新的首节点
first = newNode;
// 判断是不是第一个添加的元素
// 如果是就把last也置为新节点
// 否则把原首节点的prev指针置为新节点
if (f == null)
last = newNode;
else
f.prev = newNode;
// 元素个数加1
size++;
// 修改次数加1,说明这是一个支持fail-fast的集合
modCount++;
}
// 从队列尾添加元素
void linkLast(E e) {
// 队列尾节点
final Node<E> l = last;
// 创建新节点,新节点的prev是尾节点
final Node<E> newNode = new Node<>(l, e, null);
// 让新节点成为新的尾节点
last = newNode;
// 判断是不是第一个添加的元素
// 如果是就把first也置为新节点
// 否则把原尾节点的next指针置为新节点
if (l == null)
first = newNode;
else
l.next = newNode;
// 元素个数加1
size++;
// 修改次数加1
modCount++;
}
public void addFirst(E e) {
linkFirst(e);
}
public void addLast(E e) {
linkLast(e);
}
// 作为无界队列,添加元素总是会成功的
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
public

