浅析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) { |