浅析JDK1.7 LinkedList源码。
写在开篇
简单介绍一下LinkedList,它使用了双向循环链表作为其存储的数据结构。由于链表的特点是可以自由的添加新的元素,因此LinkedList不需要初始化大小,且列表伸缩性比ArrayList强(ArrayList只能伸展,不能收缩)。LinkedList在根据一个index查找随机节点时,会判断此index在左半区还是右半区,这样就可以选择是从头节点正向遍历,还是从尾节点反向遍历,要比只从头节点遍历的效率高一些。
类的继承结构
ArrayList继承AbstractSequentialList抽象类,实现了List(规定了List的操作规范)、Deque(双端队列)、Cloneable(可拷贝)、Serializable(可序列化)这几个接口。1
2
3public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
存储结点–Node
| 1 | private static class Node<E> { | 
成员变量
| 1 | /** | 
构造方法
LinkedList有两个构造方法。1
2
3
4
5
6
7
8
9
10
11
12
13/**
    * 空构造方法
    */
   public LinkedList() {
   }
   /**
    * 以实现了Collection接口的集合类,来初始化链表
    */
   public LinkedList(Collection<? extends E> c) {
       this();
       addAll(c);
   }
List接口的实现
add()
LinkedList有两个add(),第一个是默认在链表末尾插入新元素。1
2
3
4public boolean add(E e) {
       linkLast(e);
       return true;
   }
另一个是在指定下标插入元素。1
2
3
4
5
6
7
8public void add(int index, E element) {
       checkPositionIndex(index); // 检查下标
       if (index == size)
           linkLast(element);
       else
           linkBefore(element, node(index));
   }
接下来详细看看add()方法的核心:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25void 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++;
}
void linkBefore(E e, Node<E> succ) {
    final Node<E> pred = succ.prev; // 保存succ的前置结点
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;	// 将succ的前置结点改为新结点
    if (pred == null)
    	// 如果succ的前置结点为空,则设置新结点为头结点
        first = newNode;
    else
    	// 如果不为空,设置新结点前置结点为刚刚保存的pred
        pred.next = newNode;
    size++;
    modCount++;
}
put()
put()比较简单,直接贴源码。1
2
3
4
5
6
7public E set(int index, E element) {
       checkElementIndex(index); 
       Node<E> x = node(index);
       E oldVal = x.item;
       x.item = element; 
       return oldVal;
   }
get()
| 1 | public E get(int index) { | 
remove()
| 1 | public boolean remove(Object o) { | 
