1、简介
LinkedList继承了AbstractSequentialList,实现了List<E>, Deque<E>, Cloneable, java.io.Serializable,是一种以双向链表为数据结构的集合。允许值为null。
-
因为继承了AbstractSequentialList,所以它支持fail-fast的错误检测机制,错误检测机制见 集合部分知识点。
-
实现了Cloneable 接口,覆盖了函数 clone(),能被克隆。
-
实现java.io.Serializable 接口,这意味着支持序列化,能通过序列化去传输。
-
实现了List接口,覆盖了size()等方法
-
实现了Deque接口,覆盖了addFirst、addLast等方法
public class LinkedList extends AbstractSequentialList implements List, Deque, Cloneable, java.io.Serializable
同时,注意first节点和last节点的比较特殊的地方:
first、last可以同时为null,即这时候链表中只有一个空节点。
如果first、last节点不为null,first的前一个节点是null,last后一个节点是null。
/**
* 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;
2、部分源码
2.1 构造方法
//空参构造,空链表
public LinkedList() {
}
//带参构造,参数为Collection,用已有的集合创建链表
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
2.2 checkPositionIndex(int index)
//这两个函数的作用在于检查index是否在0和链表的长度之间,在则往下执行,否则抛出异常
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
2.3 node(int 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;
}
}
2.4 addAll(Collection<? extends E> c)
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
//见上面
checkPositionIndex(index);
//将集合Collection转化为数组
Object[] a = c.toArray();
int numNew = a.length;
//如果数组长度为0,即集合为空,则直接返回
if (numNew == 0)
return false;
Node<E> pred, succ;
//如果将所有集合中的元素都加在链表末尾
if (index == size) {
succ = null;
pred = last;
} else {
//如果不是加到末尾,succ是index所在节点,pre为index的前一个节点
succ = node(index);
pred = succ.prev;
}
将数组中的元素依次加入到链表中,index位置开始
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
//注意这里e的前一个节点是pred,所以后续中不用指定前一个节点,e的后一个节点为null
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
//当succ==null说明所有的集合元素是加到末尾的,这时候只需要指明谁是最后一个节点
if (succ == null) {
last = pred;
} else {
//否则,是加到链表中间的,则需要把数组最后一个加入到链表的节点 的下一个节点指向初始index所在节点
//初始index所在节点的前一个节点指向 数组最后一个加入到链表的节点
pred.next = succ;
succ.prev = pred;
}
//增加LinkedList的size
size += numNew;
modCount++;
return true;
}
2.5 add(E e)
//添加单个元素,直接加到链表的尾端
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
//指定e的前一个节点为链表的最后一个节点,后一个节点为null
final Node<E> newNode = new Node<>(l, e, null);
//将last指向这个刚插入的新的节点
last = newNode;
if (l == null)
//l==null 说明空链表,则指定新的节点为头节点
//为什么不用指定尾节点?因为前面 last=newNode 啦
first = newNode;
else
//与链表的最后一个节点建立联系
l.next = newNode;
size++;
modCount++;
}
2.6 linkLast(E e)
//用于添加节点到链表末端
void linkLast(E e) {
final Node<E> l = last;
//e的前一个节点是last,后一个节点是null
final Node<E> newNode = new Node<>(l, e, null);
//改变last
last = newNode;
//如果一开始链表为null
if (l == null)
//将新增的节点也指定为first
first = newNode;
else
//否则将l的下一个节点指向新的节点即可,因为新的节点的前一个节点已经在前面被指定(new Node步骤)
l.next = newNode;
size++;
modCount++;
}
2.7 linkBefore(E e, Node succ)
//将节点e添加到succ节点前面
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
//记录succ的前一个节点pred
final Node<E> pred = succ.prev;
//节点e的前一个节点为pred,后一个节点为succ,这时候还差两个箭头
final Node<E> newNode = new Node<>(pred, e, succ);
//将succ的前一个节点指向新的节点
succ.prev = newNode;
//如果前一个节点pred为null,说明这个链表只有一个节点,则指定新的节点为第一个节点
if (pred == null)
first = newNode;
else
//否则pred的下一个节点指向新的节点
pred.next = newNode;
size++;
modCount++;
}
2.8 add(int index, E element)
public void add(int index, E element) {
//检查索引是否合法,在0~size之间就合法,否则抛出异常
checkPositionIndex(index);
//如果index==size,说明要加入到链表末尾
if (index == size)
linkLast(element);
else
//否则,加入到index节点前
linkBefore(element, node(index));
}
2.9 unlinkFirst(Node 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;
//头节点的下一个节点为null,说明原链表中只有一个节点,所以last要置为null
if (next == null)
last = null;
else
//否则将新的头节点的前一个节点指向null
next.prev = null;
size--;
modCount++;
return element;
}
2.10 removeFirst()
public E removeFirst() {
final Node<E> f = first;
//如果链表为null,即头节点为null,抛出异常
if (f == null)
throw new NoSuchElementException();
//否则断开头节点和其他点的联系
return unlinkFirst(f);
}
2.11 remove()
public E remove() {
return removeFirst();
}