1.介绍
LinkedList是List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括null)。
扩展了AbstractSequentialList抽象类,实现了Deque和Queue接口。这些操作允许将链接列表用作堆栈、队列和双端队列。
2.AbstractSequentialList
要实现一个列表,程序员只需要扩展此类,并提供 listIterator 和 size 方法的实现即可。对于不可修改的列表,程序员只需要实现列表迭代器的hasNext、next、hasPrevious、previous 和index 方法即可。
对于可修改的列表,程序员应该再另外实现列表迭代器的 set 方法。对于可变大小的列表,程序员应该再另外实现列表迭代器的 remove 和add 方法。
AbstractSequentialList中的方法,add,addAll,remove,set,get方法和AbstractList一样都是基于迭代器实现的。但不同的是,在这个抽象类中没有实现自己的迭代器,由子类LinkedList自己实现。
3.Queue
除了基本的 Collection
操作外,队列还提供其他的插入、提取和检查操作。每个方法都存在两种形式:一种抛出异常(操作失败时),另一种返回一个特殊值(null 或false,具体取决于操作)。插入操作的后一种形式是用于专门为有容量限制的Queue 实现设计的;在大多数实现中,插入操作不会失败。
4.Deque
此接口定义在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或false,具体取决于操作)。插入操作的后一种形式是专为使用有容量限制的Deque 实现设计的;在大多数实现中,插入操作不能失败。
4.LinkedList
4.1 构造方法以及实现
LinkedLIst内部是由一个双端队列实现的。保存有两个头尾节点,每个节点存有前向和后向的引用。
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;
}
}
拥有2个构造器,1.空参构造器,创建了一个空的链表 2.用另一个集合初始化LinkedList。先创建了一个空链表,添加结合元素。
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray(); //将集合中元素转化为数组
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null; //处理要插入的整段元素的前向节点和后向节点
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
for (Object o : a) { //插入元素
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
4.2 基本工具方法
在LinkedList中有一些基本工具方法,LinkedFirst将元素链接在头部,linkLast将元素链接在尾部,linkBefore在指定节点前链接元素,unlinkFirst删除头节点元素,unlinkLast删除尾节点元素,unlink删除指定元素,node(index i)方法返回索引指向的节点
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++;
}
/**
* Inserts element e before non-null Node 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);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
/**
* Unlinks non-null first node f.
*/
private E unlinkFirst(Node<E> f) { //当只有一个节点时,删除后first = last = null(不考虑0个节点是因为调用时就会先判断)
// assert f == first && f != null; //有一个节点以上时,删除后first = next,且头节点的前向链接为空
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 = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
/**
* Unlinks non-null last node l.
*/
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;
}
/**
* Unlinks non-null node x.
*/
E unlink(Node<E> x) { //判断前向元素和后向元素是否为空,前向元素为空则删除后向元素应为头节点,否则删除后prev.next = next;反之类似
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
Node<E> node(int index) { //做了优化判断,当index<size/2时从前向搜索节点。否则从后向搜索节点
// 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;
}
}
4.3实现了自己的ListIterator迭代器
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned; //上一次跳过的节点
private Node<E> next; //下一次next时应跳过的节点
private int nextIndex; //下一次next时应跳过的节点的标号
private int expectedModCount = modCount;
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
public boolean hasPrevious() {
return nextIndex > 0;
}
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
此外还实现了一个反向迭代器
private class DescendingIterator implements Iterator<E> {
private final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}