public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
关于AbstractSequentialList这个类的源码可以参考:https://mp.csdn.net/postedit/88303467
List接口想必不用多说,Collection集合下的一个分支。
Deque 详请参考:https://www.cnblogs.com/bushi/p/6681543.html
下面将代码前大家一定要清除LinkedList是一个链表!!!,所以的操作都是建立在该数据结构之上定义的
transient int size = 0;
记录当前集合的长度
transient Node<E> first;
指向第一个节点的指针。
transient Node<E> last;
指向最后一个节点的指针
public LinkedList() {
}
构造一个空的链表
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
构造一个包含指定元素的列表
private void linkFirst(E e) {
//指向头节点
final Node<E> f = first;
//该新构造的节点无前驱,后继为f
final Node<E> newNode = new Node<>(null, e, f);
//第一个节点的指针设为 newNode
first = newNode;
//如果f为空 代表修改前该链表还是一个空链表
if (f == null)
//那么最后一个节点的指针也指向newNode
last = newNode;
else
f.prev = newNode;
size++;
//modCount 记录了当前链表的修改次数,这和LinkedList非线程安全有关
modCount++;
}
链接e作为第一个元素。
void linkLast(E e) {
final Node<E> l = last;
//该新节点的前驱为 l 无后继
final Node<E> newNode = new Node<>(l, e, null);
//最后一个节点的指针设为 newNode
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
和上面的相反 即 链接e作为最后一个元素。
void linkBefore(E e, Node<E> succ) {
//断言succ != null; pred 为succ的前驱
final Node<E> pred = succ.prev;
//新节点的前驱为pred 后继为succ 内容为e
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
在非null节点succ之前插入元素e,succ不能为null该方法并为做空值处理
注意:传入的参数都符合断言的要求,因为这是一个内部方法,及不对开发者公开。
private E unlinkFirst(Node<E> f) {
//断言 f == first && f != null;
final E element = f.item;//f.item 即该节点的内容(即:元素)
final Node<E> next = f.next;
// = null 的原因是好让GC回收
f.item = null;
f.next = null;
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
也就是放弃连接第一个节点,让第一个节点的后继节点成为该链表的first。注意:穿过来的f参数必定是第一个节点
private E unlinkLast(Node<E> l) {
//断言 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;
}
和上面哪个方法刚好相反及取消链接非空的最后一个节点l。
E unlink(Node<E> x) {
// 断言 x != null;
final E element = x.item;
//获取x的前驱后继
final Node<E> next = x.next;
final Node<E> prev = x.prev;
//如果 prev 为空那么代表着x为第一个节点,所以就指向改变first指向为next即可
if (prev == null) {
first = next;
} else {
//绕过x,将x的前驱的后继改为next
prev.next = next;
x.prev = null;
}
//如果next为空,代表x无后继,也就是x是last节点,所以直接将last指向改为prev即可
if (next == null) {
last = prev;
} else {
//绕过 x节点,将next的前驱改为prev
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
取消链接非空节点x。就是将x节点从该链表中移除掉。
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
返回此列表中的第一个元素。
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
返回此列表中的最后一个元素。
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
移除该链表的第一个元素
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
移除该链表的最后一个元素
public void addFirst(E e) {
linkFirst(e);
}
在此列表的开头插入指定的元素
public void addLast(E e) {
linkLast(e);
}
在此列表的结尾插入指定的元素
public boolean contains(Object o) {
return indexOf(o) != -1;
}
判断是否包含给定元素
public int size() {
return size;
}
返回当前列表长度
public boolean add(E e) {
linkLast(e);
return true;
}
将指定的元素追加到此列表的末尾
public boolean remove(Object o) {
//判断o是否为null 防止空指针异常
if (o == null) {
//从链表的开始位置遍历整个链表,直达找为该元素或者遍历完整个链表为停止
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
//移除该元素
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
//这就是为什么要做非空判断并且弄两个循环变了的原因了(即:null.equals(x.item)报错)
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
//return false 代表没找到
return false;
}
如果该集合包含给定元素,就移除掉
//index为插入当前集合的位置,c为要将所以元素都插入的哪个集合
public boolean addAll(int index, Collection<? extends E> c) {
//判断索引是否溢出当前集合
checkPositionIndex(index);
//将c转为数组赋值给 a
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred,//pred为要插入节点位置的前驱节点
succ;//succ为要插入的节点位置
//如果index == size 代表要在最后插入
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
//遍历a数组
for (Object o : a) {
@SuppressWarnings("unchecked")
//类型强转
E e = (E) o;
//实例化节点,节点的前驱为 pred 无后继
Node<E> newNode = new Node<>(pred, e, null);
//如果pred为null代表无当前节点所在位置为表头
if (pred == null)
first = newNode;
else
//把节点间链接起来
pred.next = newNode;
//pred不断移动
pred = newNode;
}
//如果succ为null则代表插入的位置是链表的末尾
if (succ == null) {
last = pred;
} else {
//如果succ不为null则代表在链表间插入,那么我们就把它重新串联起来
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
间集合c中的所有元素从指定位置index处统统添加进该链表中
public void clear() {
//从表头遍历到表尾 将节点的属性设置为null 让GC去回收
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
清空链表
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
判断参数是否是现有元素的索引。
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
判断参数是否是迭代器或添加操作的有效位置的索引。
Node<E> node(int index) {
// 断言 index为合法索引
//翻译: index < (size / 2) 从中可以看出做了算法优化
if (index < (size >> 1)) {
Node<E> x = first;
//从first节点不断调用next方法来得到指定位置的节点
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
//从last节点不断调用prev方法来得到指定位置的节点
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
返回指定位置上的节点
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
返回该对象在链表中第一次出现的位置索引
//和indexOf套路相同,只不过是讲next该为prev而已,就是倒着来
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
返回该对象在链表中最后一次出现的位置索引
public E poll() {
final Node<E> f = first;
//unlinkFirst方法即:取消链接非空的第一个节点f。
return (f == null) ? null : unlinkFirst(f);
}
检索并删除此列表的头部(第一个元素)
public boolean removeLastOccurrence(Object o) {
//只不过是从后往前遍历
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
删除此列表中最后一次出现的指定元素。如果列表不包含该元素,则不会更改。
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// 使用我们的元素初始化克隆
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
从新定义了clone方法
private static final long serialVersionUID = 876323262645176354L;
该值和序列化有关详请参考:https://www.cnblogs.com/zheting/p/7751949.html
内部类
ListIter迭代器
//实现了ListIterator 该接口比ListIter更灵活
private class ListItr implements ListIterator<E> {
//光标当前所在节点
private Node<E> lastReturned;
//
private Node<E> next;
//代表next节点在链表中的索引
private int nextIndex;
//这样定义是因为该类非线程安全的缘故
private int expectedModCount = modCount;
//指定光标位置构造迭代器
ListItr(int index) {
//断言 Index必定是合法索引
next = (index == size) ? null : node(index);
nextIndex = index;
}
//是否还能调用next返回下一位对象
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;
}
//返回随后调用 next()返回的元素的索引。
public int nextIndex() {
return nextIndex;
}
//返回由后续调用 previous()返回的元素的索引。
public int previousIndex() {
return nextIndex - 1;
}
//从列表中删除由 next()或 previous()返回的最后一个元素(可选操作)。
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++;
}
//用 指定的元素替换由 next()或 previous()返回的最后一个元素(可选操作)。
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++;
}
//该方法是JDK 1.8新增的 用于支持Lamdba表达式
//详请查看:https://blog.csdn.net/qq_37465638/article/details/83068283
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
//从当前位置迭代每一位
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
//防止多线程篡改,由于该类是非线程安全的缘故
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
节点(链表实现密不可分的一个内部类)
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;
}
}
降序迭代器
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}
就是倒着迭代,我们看看DescendingIterator这个类的实现:
private class DescendingIterator implements Iterator<E> {
//获得当前对象的ListItr迭代器,光标位置在当前链表的末尾。用于从后往前迭代
private final ListItr itr = new ListItr(size());
//哈哈,其实有点像阳奉阴违
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}