LinkedList 是一个双向链表,实现了 List 和 Deque 接口。它容许元素为空,非线程安全。java
Deque 是一个双端队列,容许2端分别添加和删除元素。JDK中的说明是这样的node
A linear collection that supports element insertion and removal at both ends. The name deque is short for "double ended queue" and is usually pronounced "deck". Most
Deque
implementations place no fixed limits on the number of elements they may contain, but this interface supports capacity-restricted deques as well as those with no fixed size limit.数组
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList 区别于 ArrayList,它是继承自 AbstractSequentialList,而且没有实现 RandomAccess 接口。安全
若是集合类是 RandomAccess 的实现,尽可能用for(int i = 0; i < size; i++) 来遍历而不要用Iterator迭代器来遍历。数据结构
反过来,若是List是 Sequence List,则最好用迭代器来进行迭代。后面会看到若是对 LinkedList 使用普通的 for 循环,由于数据结构的缘由性能会不好。dom
AbstractSequentialList 的官方说明以下ide
This class provides a skeletal implementation of the List interface to minimize the effort required to implement this interface backed by a "sequential access" data store (such as a linked list). For random access data (such as an array), AbstractList should be used in preference to this class.性能
AbstractSequentialList 提供了一个顺序访问的集合,想要随机访问的话优先使用 AbstractList 的子类。ui
transient int size = 0; /** * Pointer to first node. */ transient Node<E> first; /** * Pointer to last node. */ 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; } }
一个 Node 内部类,包含数据体自己以及一个指向前面节点的指针和一个指向后面节点的指针。this
全局的指向头和尾的 first last 指针。
LinkedList 内部是一个双向链表结构。
public LinkedList() { } public LinkedList(Collection<? extends E> c) { this(); addAll(c); } 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; }
提供了2个构造方法,无参的构造方法什么事都不作,接收一个 collection 的构造方法将新的集合放到链表的尾端,将 last 指针指向最后一个节点。
public boolean add(E e) { linkLast(e); return true; } 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++; }
add 方法调用的 linkLast 方法,方法很简单 就是新建了一个node节点放到了链表的最后。
LinkedList大多都是链表操做,代码也比较简单,看下就懂了,下面稍微列出几个方法。
// add first public void addFirst(E e) { linkFirst(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++; } // add last public void addLast(E e) { linkLast(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; else f.prev = newNode; size++; modCount++; } // 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; 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; }
如开头说的 AbstractSequentialList 不要使用随机访问的方式遍历,应该采用迭代器或者foreach(foreach 底层是迭代器)。
由于 LinkedList 是个链表,没法像数组同样直接使用下标的方式取到对应的值。
// 随机访问的方式遍历 int size = list.size(); for (int i=0; i<size; i++) { list.get(i); }
看一下它的get方法
public E get(int index) { checkElementIndex(index); return node(index).item; } Node<E> node(int 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; } }
经过 size >> 1 取到一个相对中间的值,而后比较 index 是在前面一段仍是后面一段,再按顺序遍历到指定的位置。画蛇添足。
LinkedList 的大多数API都是基于一个双向链表的操做,循环遍历的时候采用迭代器或者foreach,避免使用普通的for循环。