按照学习计划,学习理解了LinkedList的源码,同时在方法中写了详细注释(在下方)
总结
LinkedList 是一个继承自AbstractSequentialList 的 双向链表,需要实现一个抽象方法,返回一个不可变的迭代器
public abstract ListIterator<E> listIterator(int index);
线程不安全
不支持随机访问
LinkedList 实现了Deque 可以当做双端队列使用
LinkedList 没有实现RandomAccess 它的循环效率要小于迭代器
知识点
快速失败( fail-fast)
快速失败是多线程情况下,对于数据不一致的处理方式
如下所示,判断两个字段
private int expectedModCount = modCount;//fail-fast 快速失败
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
- modCount 记录LinkedList 本身的操作
- expectedModCount 记录迭代器操作,他的初始值为modCount
当迭代器内部发生了add和remove操作都会导致expectedModCount++
迭代器每次迭代,都会访问checkForComodification()方法
发现数据不一致时,立即失败,抛出ConcurrentModificationException 异常
双端队列 Deque
参考摘录自 :双端队列
- Deque 是 Double ended queue (双端队列) 的缩写,读音和 deck 一样,蛋壳。
- Deque 继承自 Queue,直接实现了它的有 LinkedList, ArayDeque, ConcurrentLinkedDeque 等。
- Deque 支持容量受限的双端队列,也支持大小不固定的。一般双端队列大小不确定。
- Deque 接口定义了一些从头部和尾部访问元素的方法。比如分别在头部、尾部进行插入、删除、获取元素。和 Queue
双端队列只允许在开始和结尾处进行操作,操作方式有:
insert 操作实例
请观察添加顺序和打印结果的不同之处:
public static void main(String[] args) {
LinkedList<String> var = new LinkedList<>();
//insert
var.offerLast("d");// 在尾结点的前面插入
var.offerFirst("b");// 在开始位置 后面插入
var.addFirst("a");//在开始位置添加
var.addLast("c"); // 添加到尾结点
var.listIterator().forEachRemaining(System.out::println);
}
打印结果:
remove 操作实例
删除指定位置:
public static void main(String[] args) {
LinkedList<String> var = new LinkedList<>();
//insert
var.offerLast("d");// 在尾结点的前面插入
var.offerFirst("b");// 在开始位置 后面插入
var.addFirst("a");//在开始位置添加
var.addLast("c"); // 添加到尾结点
var.removeFirst();
var.listIterator().forEachRemaining(System.out::println);
}
打印结果:
详细注释
import java.util.*;
import java.util.function.Consumer;
/**
* AbstractSequentialList -----------START
* This class provides a skeletal implementation of the <tt>List</tt>
* interface to minimize the effort required to implement this interface
* backed by a "sequential access" data store (such as a linked list). For
* random access data (such as an array), <tt>AbstractList</tt> should be used
* in preference to this class.<p>
* List 接口的实现, 为实现序列访问的数据结构提供了最小化的接口实现,对于支持随机访问的List,应该优先采用 AbstractList
* 最小化 = 只支持按照顺序访问 ,AbstractList 支持随机访问
* 通俗点说 LinkedList 实现 AbstractSequentialList ArrayList 实现 AbstractList
* ArrayList 实现了RandomAccess接口(这个接口只是标记支持随机访问) LinkedList没有
* 支持 RandomAccess 的对象,遍历时使用 get 比 迭代器更快
* LinkedList 没有实现RandomAccess 那么他的get效率要小于迭代器
* <p>
* This class is the opposite of the <tt>AbstractList</tt> class in the sense
* that it implements the "random access" methods (<tt>get(int index)</tt>,
* <tt>set(int index, E element)</tt>, <tt>add(int index, E element)</tt> and
* <tt>remove(int index)</tt>) on top of the list's list iterator, instead of
* the other way around.<p>
* To implement a list the programmer needs only to extend this class and
* provide implementations for the <tt>listIterator</tt> and <tt>size</tt>
* methods. For an unmodifiable list, the programmer need only implement the
* list iterator's <tt>hasNext</tt>, <tt>next</tt>, <tt>hasPrevious</tt>,
* <tt>previous</tt> and <tt>index</tt> methods.<p>
* For a modifiable list the programmer should additionally implement the list
* iterator's <tt>set</tt> method. For a variable-size list the programmer
* should additionally implement the list iterator's <tt>remove</tt> and
* <tt>add</tt> methods.<p>
* AbstractSequentialList是AbstractList 类中与随机访问类相对(相反) 的实现
* 你需要实现一个 ListIterator, 实现它的 hasNext(), hasPrevious(), next(), previous()
* 如果你想让它可修改,还需要实现 add(), remove(), set() 方法
* 然后就可以获得一个 不可变的 ListIterator
* AbstractSequentialList -----------END
* <p>
* Deque -----------START
* A linear collection that supports element insertion and removal at
* both ends. The name <i>deque</i> is short for "double ended queue"
* and is usually pronounced "deck". Most {@code Deque}
* implementations place no fixed limits on the number of elements
* they may contain, but this interface supports capacity-restricted
* deques as well as those with no fixed size limit.
* 一个支持元素插入和删除的-- 线性集合--
* deque = double ended queue
* 发音为 deck
* deque 支持容量受限的双端队列 ,也支持大小不固定,一般双端队列大小不确定
*
* <p>This interface defines methods to access the elements at both
* ends of the deque. Methods are provided to insert, remove, and
* examine the element. Each of these methods exists in two forms:
* one throws an exception if the operation fails, the other returns a
* special value (either {@code null} or {@code false}, depending on
* the operation). The latter form of the insert operation is
* designed specifically for use with capacity-restricted
* {@code Deque} implementations; in most implementations, insert
* operations cannot fail.
* 接口定义了从头部和尾部访问元素的方法,插入、删除、获取元素
* 每个操作都有两种方法,第一种在异常情况下会直接抛出异常,第二种则不会返回异常 会返回{code}
* 比如first 操作
* 1. addFirst
* 2. offerFirst
* 它写的插入操作不能失败! 实际是大多数情况下不能失败??
* Deque ----------END
* <p>
* <p>
* <p>
* LinedList 是一个继承自AbstractSequentialList 的 双向链表,线程不安全(非同步的) , 不支持随机访问
* LinedList 实现了Deque 可以当做双端队列使用
*
* @author 李东
* @version 1.0
* @date 2020/1/10 21:55
*/
public class MyLinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
/**
* linkedList 拥有三个成员变量
*/
transient int size = 0;// 容量
transient Node<E> first;// 头结点
transient Node<E> last;// 尾节点
/**
* 链表节点的定义
*
* @param <E>
*/
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;
}
}
/**
* AbstractSequentialList 类的实现
*
* @return 不可变的 ListIterator
*/
@Override
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
/**
* An iterator for lists that allows the programmer
* to traverse the list in either direction, modify
* the list during iteration, and obtain the iterator's
* current position in the list. A {@code ListIterator}
* has no current element; its <I>cursor position</I> always
* lies between the element that would be returned by a call
* to {@code previous()} and the element that would be
* returned by a call to {@code next()}.
* An iterator for a list of length {@code n} has {@code n+1} possible
* cursor positions, as illustrated by the carets ({@code ^}) below:
* <p>
* 运行的操作:
* 1. 允许任意方向的遍历 也就是说
* ListIterator 可以前后迭代
* Iterator 只能向前迭代
* 2. 迭代运行期间支持修改
* ListIterator 可以 set 和add
* Iterator 只能删除
* 3. 列表当前位置 总是位于调用返回的之间
* 这个位置称之为游标
* 他第一次存在于 0 这个下标之前
* 他的总大小为 n+1
* <PRE>
* Element(0) Element(1) Element(2) ... Element(n-1)
* cursor positions: ^ ^ ^ ^ ^
* </PRE>
*/
private class ListItr implements ListIterator<E> {
/**
* 四个成员变量
*/
private Node<E> lastReturned;//上一次迭代的节点
private Node<E> next; //下一个节点
private int nextIndex;//记录当前游标的位置,没有下标的概念
private int expectedModCount = modCount;//fail-fast 快速失败
/**
* 返回一个固定位置的迭代器
*/
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
/**
* * Returns {@code true} if this list iterator has more elements when
* * traversing the list in the forward direction. (In other words,
* * returns {@code true} if {@link #next} would return an element rather
* * than throwing an exception.)
*
* @return 下个节点是否存在
*/
public boolean hasNext() {
return nextIndex < size;
}
/**
* Returns the next element in the list and advances the cursor position.
* This method may be called repeatedly to iterate through the list,
* or intermixed with calls to {@link #previous} to go back and forth.
* (Note that alternating calls to {@code next} and {@code previous}
* will return the same element repeatedly.)
* <p>
* 返回下个节点 并向前移动游标
* 这个方法可以用来遍历列表
* 也可以使用 {@link #previous} 方法
*
* @return
*/
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
/**
* Returns {@code true} if this list iterator has more elements when
* traversing the list in the reverse direction. (In other words,
* returns {@code true} if {@link #previous} would return an element
* rather than throwing an exception.)
*
* @return {@code true} if the list iterator has more elements when
* traversing the list in the reverse direction
* <p>
* 判断游标前面是否有元素,循环就完事了
*/
public boolean hasPrevious() {
return nextIndex > 0;
}
/**
* Returns the previous element in the list and moves the cursor
* position backwards. This method may be called repeatedly to
* iterate through the list backwards, or intermixed with calls to
* {@link #next} to go back and forth. (Note that alternating calls
* to {@code next} and {@code previous} will return the same
* element repeatedly.)
*
* @return the previous element in the list
* @throws NoSuchElementException if the iteration has no previous
* element
* <p>
* <p>
* 返回游标前面的元素,同时游标前移一位
* 功能和next 相反
*/
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
/**
* Returns the index of the element that would be returned by a
* subsequent call to {@link #next}. (Returns list size if the list
* iterator is at the end of the list.)
*
* @return the index of the element that would be returned by a
* subsequent call to {@code next}, or list size if the list
* iterator is at the end of the list
* <p>
* <p>
* 返回游标后边元素的索引位置
*/
public int nextIndex() {
return nextIndex;
}
/**
* /**
* Returns the index of the element that would be returned by a
* subsequent call to {@link #previous}. (Returns -1 if the list
* iterator is at the beginning of the list.)
*
* @return the index of the element that would be returned by a
* subsequent call to {@code previous}, or -1 if the list
* iterator is at the beginning of the list
* <p>
* 返回游标前面元素的位置
* 默认为 -1
* 如果木有元素 会抛出异常
* NoSuchElementException 找不到元素
*/
public int previousIndex() {
return nextIndex - 1;
}
/**
* Removes from the list the last element that was returned by {@link
* #next} or {@link #previous} (optional operation). This call can
* only be made once per call to {@code next} or {@code previous}.
* It can be made only if {@link #add} has not been
* called after the last call to {@code next} or {@code previous}.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this list iterator
* @throws IllegalStateException if neither {@code next} nor
* {@code previous} have been called, or {@code remove} or
* {@code add} have been called after the last call to
* {@code next} or {@code previous}
* 从列表中删除 next 或者 previous 方法返回的数据
* 如果 未使用迭代中的 next 或者 previous 会抛出异常 IllegalStateException
*/
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++;
}
/**
* Replaces the last element returned by {@link #next} or
* {@link #previous} with the specified element (optional operation).
* This call can be made only if neither {@link #remove} nor {@link
* #add} have been called after the last call to {@code next} or
* {@code previous}.
*
* @param e the element with which to replace the last element returned by
* {@code next} or {@code previous}
* @throws UnsupportedOperationException if the {@code set} operation
* is not supported by this list iterator
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this list
* @throws IllegalArgumentException if some aspect of the specified
* element prevents it from being added to this list
* @throws IllegalStateException if neither {@code next} nor
* {@code previous} have been called, or {@code remove} or
* {@code add} have been called after the last call to
* {@code next} or {@code previous}
*
* 给最后一次操作的值赋值
* 只能在 迭代期间调用 ,并且没有进行remove操作
*
*/
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++;
}
//一个循环消费方法
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();
}
}
/**
* Returns the (non-null) Node at the specified element index.
* <p>
* 返回指定位置的元素
*/
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;
}
}
/**
* Unlinks non-null node x.
*清空指定数据
*/
E unlink(Node<E> x) {
// 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;
}
/**
* Links e as last element.
* 将元素e 添加到尾部节点
*/
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.
* 在非空的节点succ 前插入 e
*/
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++;
}
/**
* Inserts the specified element at the beginning of this list.
* 将指定的元素添加到链表开始位置
* @param e the element to add
*/
@Override
public void addFirst(E e) {
linkFirst(e);
}
/**
* Links e as first element.
* e 添加到开始
*/
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++;
}
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #add}.
*
* @param e the element to add
*
* 将e 添加到结尾
*/
@Override
public void addLast(E e) {
linkLast(e);
}
// Deque operations
/**
* Inserts the specified element at the front of this list.
* 将 e 插入此列表的前面。
* @param e the element to insert
* @return {@code true} (as specified by {@link Deque#offerFirst})
* @since 1.6
*/
@Override
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
/**
* Inserts the specified element at the end of this list.
*将 e 插入此列表的末尾
* @param e the element to insert
* @return {@code true} (as specified by {@link Deque#offerLast})
* @since 1.6
*/
@Override
public boolean offerLast(E e) {
addLast(e);
return true;
}
/**
* Removes and returns the first element from this list.
* 删除链表开始节点
* @return the first element from this list
* @throws NoSuchElementException if this list is empty
*/
@Override
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
/**
* Unlinks non-null first 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;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
@Override
public E removeLast() {
return null;
}
@Override
public E pollFirst() {
return null;
}
@Override
public E pollLast() {
return null;
}
@Override
public E getFirst() {
return null;
}
@Override
public E getLast() {
return null;
}
@Override
public E peekFirst() {
return null;
}
@Override
public E peekLast() {
return null;
}
@Override
public boolean removeFirstOccurrence(Object o) {
return false;
}
@Override
public boolean removeLastOccurrence(Object o) {
return false;
}
@Override
public boolean offer(E e) {
return false;
}
@Override
public E remove() {
return null;
}
@Override
public E poll() {
return null;
}
@Override
public E element() {
return null;
}
@Override
public E peek() {
return null;
}
@Override
public void push(E e) {
}
@Override
public E pop() {
return null;
}
@Override
public int size() {
return 0;
}
@Override
public Iterator<E> descendingIterator() {
return null;
}
/**
* Tells if the argument is the index of a valid position for an
* iterator or an add operation.
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
/**
* Constructs an IndexOutOfBoundsException detail message.
* Of the many possible refactorings of the error handling code,
* this "outlining" performs best with both server and client VMs.
*/
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
/**
* 检测索引位置是否存在
*/
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}