数据结构

 如图所示,LinkedList 底层是基于双向链表实现的,LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。
 类图:
 
源码分析
重要成员
    transient int size = 0;
    /**
     * Pointer to first node.
     */
    transient Node<E> first;
    /**
     * Pointer to last node.
     */
    transient Node<E> last;
Node静态内部类
    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;
        }
    }
add方法
添加到链尾
    /**
     * Appends the specified element to the end of this list.
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    /**
     * Links e as last element.
     */
    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++;
    } 
可见每次插入都是移动指针,和 ArrayList 的拷贝数组来说效率要高上不少。
添加到链表指定位置
    /**
     * Inserts the specified element at the specified position in this list.
     */
    public void add(int index, E element) {
        checkPositionIndex(index);//检查位置是否合法
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }
    /**
     * 插入到指定链表位置
     * Inserts element e before non-null Node 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++;
    }
可见添加到指定位置,需要遍历n/2找到指定位置的元素,然后移动指针。
查询方法
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    /**
     * Returns the (non-null) Node at the specified element index.
     */
    Node<E> node(int index) {
        // assert isElementIndex(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;
        }
    }
上述代码,利用了双向链表的特性,如果index离链表头比较近,就从节点头部遍历。否则就从节点尾部开始遍历。使用空间(双向链表)来换取时间。
node()会以O(n/2)的性能去获取一个结点。这样的效率是非常低的,特别是当 index 越接近 size 的中间值时。
序列化
LinkedList自定义了序列化方式
  /**
     * Saves the state of this {@code LinkedList} instance to a stream
     * (that is, serializes it).
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // Write out any hidden serialization magic
        s.defaultWriteObject();
        // Write out size 写入链表长度
        s.writeInt(size);
        // Write out all elements in the proper order. 依次写入每个节点元素
        for (Node<E> x = first; x != null; x = x.next)
            s.writeObject(x.item);
    }
    /**
     * Reconstitutes this {@code LinkedList} instance from a stream
     * (that is, deserializes it).
     */
    @SuppressWarnings("unchecked")
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden serialization magic
        s.defaultReadObject();
        // Read in size
        int size = s.readInt();
        // Read in all elements in the proper order.
        for (int i = 0; i < size; i++)
            linkLast((E)s.readObject());
    }
Deque
LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问、插入、移除和检查元素的方法。
每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。
 如下:
 
FIFO
LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下表的方法等价:
| 队列方法 | 等效方法 | 
|---|---|
| add(e) | addLast(e) | 
| offer(e) | offerLast(e) | 
| remove() | removeFirst() | 
| poll() | pollFirst() | 
| element() | getFirst() | 
| peek() | peekFirst() | 
LIFO
LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:
| 栈方法 | 等效方法 | 
|---|---|
| push(e) | addFirst(e) | 
| pop() | removeFirst() | 
| peek() | peekFirst() | 
总结
LinkedList 插入,删除都是移动指针效率很高。
 查找需要进行遍历查询,效率较低