LinkedList是 List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。所有操作都是按照双重链接列表的需要执行的。在列表中遍历索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。
注意,此实现不是同步(线程安全)的。如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。(结构修改指添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法来“包装”该列表。最好在创建时完成这一操作,以防止对列表进行意外的不同步访问,如下所示:
List list = Collections.synchronizedList(new LinkedList(...));
此类的 iterator 和 listIterator 方法返回的迭代器是快速失败 的:在迭代器创建之后,如果从结构上对列表进行修改,除非通过迭代器自身的remove 或 add 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不冒将来不确定的时间任意发生不确定行为的风险。
注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何硬性保证。快速失败迭代器尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序的方式是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。
2、LinkedList构造实现以及重要方法
对LinkdeList而言,底层实现是通过一个无头结点的双向链表,其所有操作都遵循双向链表。其基本结构为:
主要的操作方法有 void linkFirst(E e),void linkLast(E e), void linkBefore(E e, Node<E> succ) ,E unlinkFirst(Node<E> f), E unlinkLast(Node<E> l)。这些方法实现了链表的基本操作,可以看到他们都是私有的,其他的方法通过这几个基本方法实现。下面来分析LinkedList源码:
1)构造器
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
2)链表节点 Node
每个节点中记录数据项item,以及前一个节点prev和后一个节点next。
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;
}
}
3)linkFirst(e: E): void 从表头添加元素方法
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f); //构造新节点,保存元素e
first = newNode;
if (f == null) //如果是空链表,那么设置last 指向新节点
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
4) linkLast(e: E): void 在链表尾部添加元素方法
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null); //构造新节点,保存元素e
last = newNode;
if (l == null) //如果是空链表,那么设置first 指向新节点
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
5) linkBefore(e: E, succ: Node<E>): void 在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); //构造新节点,保存元素e
succ.prev = newNode; //将新节点插入到succ前面
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
6) unlinkFirst(f: Node<E>): E 将头结点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
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
7) unlinkLast(l: Node<E>): E 删除尾节点方法
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;
}