网上的LinkedList源码分析我看到的基本应该都不是Java8的(我猜现在应该挺多了,文章是从我原来的博客转移过来的,一年多前写的了)。
先看下这个类的介绍:
/**
* Doubly-linked list implementation of the {@code List} and {@code Deque}
* interfaces. Implements all optional list operations, and permits all
* elements (including {@code null}).
*
* <p>All of the operations perform as could be expected for a doubly-linked
* list. Operations that index into the list will traverse the list from
* the beginning or the end, whichever is closer to the specified index.
*
* <p><strong>Note that this implementation is not synchronized.</strong>
* If multiple threads access a linked list concurrently, and at least
* one of the threads modifies the list structurally, it <i>must</i> be
* synchronized externally. (A structural modification is any operation
* that adds or deletes one or more elements; merely setting the value of
* an element is not a structural modification.) This is typically
* accomplished by synchronizing on some object that naturally
* encapsulates the list.
*
* If no such object exists, the list should be "wrapped" using the
* {@link Collections#synchronizedList Collections.synchronizedList}
* method. This is best done at creation time, to prevent accidental
* unsynchronized access to the list:<pre>
* List list = Collections.synchronizedList(new LinkedList(...));</pre>
*
* <p>The iterators returned by this class's {@code iterator} and
* {@code listIterator} methods are <i>fail-fast</i>: if the list is
* structurally modified at any time after the iterator is created, in
* any way except through the Iterator's own {@code remove} or
* {@code add} methods, the iterator will throw a {@link
* ConcurrentModificationException}. Thus, in the face of concurrent
* modification, the iterator fails quickly and cleanly, rather than
* risking arbitrary, non-deterministic behavior at an undetermined
* time in the future.
*
* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
* as it is, generally speaking, impossible to make any hard guarantees in the
* presence of unsynchronized concurrent modification. Fail-fast iterators
* throw {@code ConcurrentModificationException} on a best-effort basis.
* Therefore, it would be wrong to write a program that depended on this
* exception for its correctness: <i>the fail-fast behavior of iterators
* should be used only to detect bugs.</i>
*
* <p>This class is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
*
* @author Josh Bloch
* @see List
* @see ArrayList
* @since 1.2
* @param <E> the type of elements held in this collection
*/
双链表实现,支持List,Deque,不同步,fail-fast behavior。
fail-fast behavior指面对并发的修改,迭代器很快会挂掉(ConcurrentModificationException),避免在将来不确定的时间发生不确定的行为,不过上面也说了,它只是尽力而为(没错,和网络层提供的尽力而为的服务意思差不多),别指望它来保证你程序的正确性。
类定义:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
如果你对Cloneable接口或Java序列化不知道,可以去了解下相关知识。
Java8的变化,头结点去除了,不过有指向第一个和最后一个节点的引用,还有个记录链表节点数量的变量:
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
可以看到上面三个成员变量都加了transient关键字修饰,我们知道transient关键字的作用是让这个成员变量不能被序列化,那这里为什么要这样做?
我暂时也不是很清楚,可以看看Effective Java第11章第75条。。。
维护指向第一个和最后一个节点两个引用有很多好处,下面说一些:
根据索引查找某一节点时,可以根据索引值决定是从前开始遍历效率高,还是从后开始遍历效率高,源码中的体现如下:
/**
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(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;
}
}
方便的实现头插法,尾插法:
/**
* Links e as first element.
*/
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++;
}
/**
* 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++;
}
方便的从头尾插入,移除元素(就不贴源码了,要不然有凑字数的嫌疑。。。)。
构造函数也有些变化,以前第一个构造函数是用来帮助构造循环链表的,现在空空如也(因为维护了指向第一个和最后一个节点两个引用,所以可能不需要循环链表了吧):
/**
* Constructs an empty list.
*/
public LinkedList() {
}
具体节点类(以前叫Entry):
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;
}
}
至于增删查改之类的肯定有的啦,这些就不说了,可以看我这篇文章实现的一个简陋版:
Java实现单链表的一些操作
因为支持头插法,尾插法增加节点。
/**
* Inserts the specified element at the beginning of this list.
*
* @param e the element to add
*/
public void addFirst(E e) {
linkFirst(e);
}
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #add}.
*
* @param e the element to add
*/
public void addLast(E e) {
linkLast(e);
}
所以你要用它实现栈和队列的特性都可以。
默认尾插法:
public boolean add(E e) {
linkLast(e);
return true;
}
这次先写到这里吧。