在上一篇中,我们分析了ArrayList的源码,我们知道ArrayList底层是使用数组来组织数据的,接下来我们将继续分析List接口的另外一个实现类:LinkedList。与ArrayList不同之处,LinkedList底层使用双向链表来组织数据的,每个结点有三个域,分别为:储存数据的item域、指向下一个结点的next域以及指向前一个结点的prev域,下面是底层结点的源码:
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;
}
}
首先我们先来分析LinkedList的构造方法:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
// 集合大小
transient int size = 0;
// 指向第一个结点
transient Node<E> first;
// 指向尾结点
transient Node<E> last;
// 无参构造函数
public LinkedList() {
}
// 使用另外一个集合来初始化LinkedList
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
}
从上述源码中我们可以发现,LinkedList继承自 AbstractSequentialList,AbstractSequentialList是AbstractList的子类,它重写了AbstractList中的一些方法,使得更快的实现顺序集合,比如LinkedList。下面是AbstractSequentialList的源码:
public abstract class AbstractSequentialList<E> extends AbstractList<E> {
protected AbstractSequentialList() {
}
public E get(int index) {
try {
return listIterator(index).next();
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public E set(int index, E element) {
try {
ListIterator<E> e = listIterator(index);
E oldVal = e.next();
e.set(element);
return oldVal;
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public void add(int index, E element) {
try {
listIterator(index).add(element);
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public E remove(int index) {
try {
ListIterator<E> e = listIterator(index);
E outCast = e.next();
e.remove();
return outCast;
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public boolean addAll(int index, Collection<? extends E> c) {
try {
boolean modified = false;
ListIterator<E> e1 = listIterator(index);
for (E e : c) {
e1.add(e);
modified = true;
}
return modified;
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public Iterator<E> iterator() {
return listIterator();
}
public abstract ListIterator<E> listIterator(int index);
}
这些方法都比较简单,都是通过List迭代器来操作的,因此子类只需要重写listIterator方法即可完成一个简单的顺序List了。
另外,LinkedList除了实现了List接口还实现了Deque接口,Deque接口规定了一个双端队列的规范,还包含的栈的push与pop操作,故Deque也可以当做一个栈来使用。此外Deque接口继承自Queue接口,Queue是一个先进先出的队列接口。
因此LinkedList还可以当做双端队列(Deque<E> deque = new LinkedList<>())、栈(Deque<E> stack = new LinkedList<>())以及队列 (Queue<E> queue = new LinkedList<>())来使用,它们的底层都是使用双向链表来实现的。Java还提供了底层基于数组的Deque实现类ArrayDeque。关于ArrayDeque的源码解析我们稍后在来解析。现在先看看Queue以及Deque接口提供了那些方法。
Queue接口源码如下:
public interface Queue<E> extends Collection<E> {
boolean add(E e);
boolean offer(E e);
E remove();
E poll();
E element();
E peek();
}
Queue扩展了Collection接口,它的主要操作有三种:
1、在尾部添加元素(add,offer)。
2、查看头部元素(element,peek).返回头部元素,但不改变队列。
3、删除头部元素(remove,poll),返回头部元素,并且从队列中删除。
可以看到每一种操作都有两种形式,区别在于对特殊情况的处理不同。特殊情况指的是队列为空或者队列为满,为空容易理解,为满指的是队列大小受到限制而且已经占满了。在LinkedList的实现中,队里的长度没有限制,但是别的Queue的实现可能有。在队列为空时,element和remove会抛出NoSuchElementException异常,而peek和poll返回特殊值null。在队列为满时,add会抛出IllegalArgumentException异常,而offer知识返回false(JDK 7,别的版本可能不一样,JDk8也是抛出异常)。
双端队列Deque扩展了队列Queue,队列Queue只能在队头删除元素,队尾插入元素,而双端队列Deque在两头都可以插入、删除元素。Deque扩展Queue的源码如下:
public interface Deque<E> extends Queue<E> {
void addFirst(E e);
void addLast(E e);
boolean offerFirst(E e);
boolean offerLast(E e);
E removeFirst();
E removeLast();
E pollFirst();
E pollLast();
E getFirst();
E getLast();
E peekFirst();
E peekLast();
boolean removeFirstOccurrence(Object o);
boolean removeLastOccurrence(Object o);
// 栈的方法
void push(E e);
E pop();
E peek();
// 迭代器
Iterator<E> iterator();
Iterator<E> descendingIterator();
}
操作的含义与方法名是一样的,同样每种操作的提供了两个版本,区别与Queue中的一样。
明白了LinkedList的继承体系之后我们再来看LinkedList底层的实现原理。在介绍LinkedList的构造方法时我们给出了LinkedList中最主要的三个成员变量:size、first与last。LinkedList中所有的public方法都是围绕着这三个变量来展开的。
先看几个重要的私有方法:
// 添加对象e到链表的头部
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode; // 更新头结点
if (f == null) // 如果加入结点时,原链表为空,则同时也更新尾指针last,指向newNode
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
// 添加对象e到链表的尾部
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
// 添加对象e到结点succ的前面
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
// 删除头结点(传入的参数f就是头结点)
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
// 删除尾结点(传入的参数l就是尾结点)
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
// 删除结点x
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
// 更具索引值返回对应的结点
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) { // 如果索引值小于 size/2 从前往后找
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else { // 索引值大于 size/2 从后往前找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
这些都是双向链表的基本操作,如果觉得困难的话先去补一补双向链表的知识吧。
// 返回首元素,为空时抛出异常 继承自Deque
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
// 返回末尾元素,为空时抛出异常, 继承自Deque
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
// 删除首元素 ,为空时抛出异常,继承自Deque
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
// 删除末尾元素,为空时抛出异常,继承自Deque
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
// 在标头插入元素 , 继承自 Deque
public void addFirst(E e) {
linkFirst(e);
}
// 在表尾插入元素, 继承自Deque
public void addLast(E e) {
linkLast(e);
}
// 在表尾插入元素
public boolean add(E e) {
linkLast(e);
return true;
}
// 在对应的索引处插入元素
public void add(int index, E element) {
checkPositionIndex(index); // 检测插入位置 index 是否合法
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
// 返回表的长度
public int size() {
return size;
}
// 根据值来删除元素
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
// 根据索引来删除元素
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index)); // 先获取对应索引的对象,然后再删除
}
// 是否包含元素
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
// 返回元素对应的索引
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
// 根据索引返回对应值
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
// 修改索引位置的值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
// 批量修改操作
// 增加集合内的所有元素早末尾
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
// 在指定位置增加
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
// 清除结点
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
总体来说,LinkedList的源码还是比较简单的,基本都是一些简单的链表操作,上面并没有列出LinkedList的所有操作,其余的操作也都比较简单,就不浪费篇幅了。