按照學習計劃,學習理解了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));
}
}