LinkedList 与 ArrayList 一样实现 List 接口,只是 ArrayList 是 List 接口的大小可变数组的实现,LinkedList 是 List 接口链表的实现。基于链表实现的方式使得 LinkedList 在随机插入和删除时更优于 ArrayList,而随机访问则比 ArrayList 逊色些。本文主要通过源码分析 LinkedList。

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;

	// 节点内部类:有前、后两个指针
	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 中的添加操作很多,常用方法如下:

add(E, e) 和 addLast:将指定元素添加到此链表的末尾处。

// 添加操作
public boolean add(E e) {
	linkLast(e);
	return true;
}
 
 
// 添加到尾节点
public void addLast(E e) {
	linkLast(e);
}


// 从队列尾添加元素
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++;
}

addFirst:将新元素添加到首节点处:

// 添加到首节点
public void addFirst(E e) {
	linkFirst(e);
}

// 从队列首添加元素
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++;
}

插入指定的位置处:add(int index, E element)

// 在指定index位置处添加元素
public void add(int index, E element) {
    // 判断是否越界
    checkPositionIndex(index);
    // 如果index是在队列尾节点之后的一个位置
    // 把新节点直接添加到尾节点之后
    // 否则调用linkBefore()方法在中间添加节点
    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

// 在节点succ之前添加元素
void linkBefore(E e, Node<E> succ) {
   
    // 找到待添加节点的前置节点
    final Node<E> pred = succ.prev;
    // 在其前置节点和后继节点之间创建一个新节点
    final Node<E> newNode = new Node<>(pred, e, succ);
    // 修改后继节点的前置指针指向新节点
    succ.prev = newNode;
    // 判断前置节点是否为空
    // 如果为空,说明是第一个添加的元素,修改first指针
    // 否则修改前置节点的next为新节点
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    // 修改元素个数
    size++;
    // 修改次数加1
    modCount++;
}


// 寻找index位置的节点
Node<E> node(int index) {
    // 因为是双链表
    // 所以根据index是在前半段还是后半段决定从前遍历还是从后遍历
    // 这样index在后半段的时候可以少遍历一半的元素
    if (index < (size >> 1)) {
        // 如果是在前半段
        // 就从前遍历
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        // 如果是在后半段
        // 就从后遍历
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

remove(Object o):移除链表中指定的元素

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;
}

// 删除指定节点x
E unlink(Node<E> x) {
    // x的元素值
    final E element = x.item;
    // x的前置节点
    final Node<E> next = x.next;
    // x的后置节点
    final Node<E> prev = x.prev;

    // 如果前置节点为空
    // 说明是首节点,让first指向x的后置节点
    // 否则修改前置节点的next为x的后置节点
    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    // 如果后置节点为空
    // 说明是尾节点,让last指向x的前置节点
    // 否则修改后置节点的prev为x的前置节点
    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    // 清空x的元素值,协助GC
    x.item = null;
    // 元素个数减1
    size--;
    // 修改次数加1
    modCount++;
    // 返回删除的元素
    return element;
}

removeFirst():移除链表的首节点

// remove的时候如果没有元素抛出异常
public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}


// 删除首节点
private E unlinkFirst(Node<E> f) {
    // 首节点的元素值
    final E element = f.item;
    // 首节点的next指针
    final Node<E> next = f.next
    f.item = null; // help GC
    f.next = null; // help GC
    // 把首节点的next作为新的首节点
    first = next;
    // 如果只有一个元素,删除了,把last也置为空
    // 否则把next的前置指针置为空
    if (next == null)
        last = null;
    else
        next.prev = null;
    // 元素个数减1
    size--;
    // 修改次数加1
    modCount++;
    // 返回删除的元素
    return element;
}

removeFirst():移除链表的尾节点

// remove的时候如果没有元素抛出异常
public E removeLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return unlinkLast(l);
}


// 删除尾节点
private E unlinkLast(Node<E> l) {
    // 尾节点的元素值
    final E element = l.item;
    // 尾节点的前置指针
    final Node<E> prev = l.prev
    l.item = null; // help GC
    l.prev = null; // help GC
    // 让前置节点成为新的尾节点
    last = prev;
    // 如果只有一个元素,删除了把first置为空
    // 否则把前置节点的next置为空
    if (prev == null)
        first = null;
    else
        prev.next = null;
    // 元素个数减1
    size--;
    // 修改次数加1
    modCount++;
    // 返回删除的元素
    return element;
}

总结:

(1)LinkedList是一个以双向链表实现的List;

(2)LinkedList在队列首尾添加、删除元素非常高效,时间复杂度为O(1);

(3)LinkedList在中间添加、删除元素比较低效,因为需要遍历链表,找到添加、删除元素的位置,时间复杂度为O(n);

(4)LinkedList不支持随机访问,所以访问非队列首尾的元素比较低效。