本文內容:java
1、LinkedList概述node
2、LinkedList源碼實現數據結構
LinkedList概述ide
LinkedList底層是雙向循環鏈表實現的。先看一下LinkedList的繼承圖:函數
由繼承關係圖能夠看到,LinkedList同時實現了List和Queue(Deque)的功能,也就是說LinkedList既能夠作List,也能夠當雙端隊列使用。優化
這裏還有個很奇怪的繼承:LinkedList同時繼承了List,也繼承了AbstractList。但AbstractList已經繼承了List,爲何LinkedList還要直接繼承List呢?stackoverflow有過討論(Why does ArrayList have 「implements List」?) 或許只有Josh Bloch才知道吧。或許他寫的時候知道,但如今只有上帝知道了吧。this
源碼實現spa
LinkedList定義
.net
linkedList類的定義以下:code
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList繼承AbstractSequentialList,實現List,Deque,Cloneable,Serialiable接口。下面簡要說明一下這幾個類及接口的做用。
Cloneable接口
Cloneable有什麼用呢?打開源碼,發現裏面只有一個空接口,沒有具體的實現:
public interface Cloneable { }
再看一下注釋:
A class implements the Cloneable interface to indicate to the Object.clone() method that it is legal for that method to make a field-for-field copy of instances of that class
大意是說實現Cloneable接口就意味這個類將會會實現Object.clone()方法。LinkedList實現的是淺拷貝(clone方法詳解能夠看這裏http://blog.csdn.net/zhangjg_blog/article/details/18369201)
等一下,Cloneable只是一個接口並無具體的方法,若是個人類繼承了Cloneable接口,但沒實現clone()方法,會如何呢?
Invoking Object's clone method on an instance that does not implement the Cloneable interface results in the exception CloneNotSupportedException being thrown.
大意是說,若是沒實現clone方法,在調用clone()方法時,會拋出CloneNotSupportedException異常。
由上分析能夠看出,LinkedList是能夠用clone方法的。LinkedList的clone實現後面再分析。
Serializable接口
serializable接口代表該類是能夠序列化的,LinkedList的序列化後面分析。
List、Deque接口
鏈表和雙端隊列的實現
AbstractSequentialList類
這是一個抽象類,把線性List的可公用的類抽象到裏面,主要是給順序訪問的list(如LinkedList)提供模擬隨機訪問的方法。這種方法在平常編寫代碼中也是常常用到的:用接口作規範,用抽象類實現大部分通用功能,而後繼承抽象類實現各個不一樣的具體功能。
LinkedList構造函數
public LinkedList() { }
很好,什麼都沒有。
add方法
public boolean add(E e) { linkLast(e); return true; }
add方法經過調用linkLast將新元素添加到鏈表的尾部。
/** * Links e as last element. */ void linkLast(E e) { final Node<E> l = last; //1 final Node<E> newNode = new Node<>(l, e, null);//2 last = newNode;//3 if (l == null)//4 first = newNode; else l.next = newNode; //5 size++; modCount++; }
原來LinkedList的元素存放在Node中,這是一個定義在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; } }
linkLast是個很中規中矩的鏈表尾部添加元素方法,其實現添加一個方法以下:
獲取指向尾部元素l,
2 . 建立一個新元素
3 .將新元素設成新的尾部元素
4 .若是l爲空,證實鏈表爲空,因此將這個元素也設置成頭部元素,不然將l的next指向新的該node
5.size,modCount自增
By The Way!!!! modCount的做用是什麼?
modCount定義在LinkedList的間接父類AbstractList中
protected transient int modCount = 0;
The number of times this list has been structurally modified. Structural modifications are those that change the size of the list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.
This field is used by the iterator and list iterator implementation returned by the iterator and listIterator methods. If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations. This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.
Use of this field by subclasses is optional. If a subclass wishes to provide fail-fast iterators (and list iterators), then it merely has to increment this field in its add(int, E) and remove(int) methods (and any other methods that it overrides that result in structural modifications to the list). A single call to add(int, E) or remove(int) must add no more than one to this field, or the iterators (and list iterators) will throw bogus ConcurrentModificationExceptions. If an implementation does not wish to provide fail-fast iterators, this field may be ignored.
看一下源碼中的註釋,大意是說modCount是記錄list大小改變的次數。主要提供給iterator來實現fail-fast。在分析Iterator的時候咱們就會看到其作用了。
get方法
public E get(int index) { checkElementIndex(index); return node(index).item; }
先檢查index是否在知足要求的範圍,不知足將拋出IndexOutOfBoundsException異常
private void checkElementIndex(int index) { if (!isElementIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * Tells if the argument is the index of an existing element. */ private boolean isElementIndex(int index) { return index >= 0 && index < size; }
調用node方法返回指定的元素。這裏作了一點優化,若是index小於元素個數的一半,則從左到右查找,若是index大於元素個數的一半,則從右到左查找。
/** * Returns the (non-null) Node at the specified element 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; } }
remove方法
public boolean remove(Object o) { 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) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; }
看源碼,remove方法移除的是第一個出現的元素。若是移除的元素存在,則返回true,不然返回false。移除的操做在unlink方法中。
/** * 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; }
這種刪除鏈表元素的方法任何一本數據結構都差很少,不解釋了。
Iterator及ListIterator接口分析
咱們常見的容器都有iterator()方法,鏈表還有listIterator(),它們的繼承關係以下:
由以上繼承圖能夠看出,Iterator接口沒有往回遍歷的方法,而ListIterator擴充了往回遍歷的方法。下面說下ListIterator和Iteraotr在LinkedList的實現。
listIterator方法
public ListIterator<E> listIterator() { return listIterator(0); }
這方法定義在AbstractList中,返回listIteraotr(0)做爲默認的iterator。
!!!注意:在LinkedList的listIterator()調用的listIterator(0)並非AbstractList中的實現,而是經過繼承在LinkedList中的實現.
public ListIterator<E> listIterator(int index) { checkPositionIndex(index); return new ListItr(index); } private void checkPositionIndex(int index) { if (!isPositionIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * 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; }
先檢查index的範圍,注意,合法範圍是[0,size] (爲何不是[0,size)呢?看下面分析!)。而後建立一個ListItr對象返回。ListItr是LinkedList的一個內部類,其定義以下:
private class ListItr implements ListIterator<E>
ListItr構造函數:
private Node<E> lastReturned = null; private Node<E> next; private int nextIndex; private int expectedModCount = modCount; ListItr(int index) { // assert isPositionIndex(index); next = (index == size) ? null : node(index); nextIndex = index; }
構造函數是next和nextIndex的賦值,繼續看下去,hasNext判斷下個元素是否存在
public boolean hasNext() { return nextIndex < size; }
繼續看next方法
public E next() { checkForComodification(); if (!hasNext()) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; return lastReturned.item; }
看到這裏,結合hasNext和Next終於知道爲何isPositionIndex的範圍檢查是[0,size]而不是[0,size)了。index=size表示着已經到元素最後,沒發讀取下個元素了。繼續看代碼
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++; }
每次都要判斷lastReturned,而lastReturned只有在next和previous中會被賦值,所以,要刪除元素,要先next()/previous(),而後才能remove。不然拋異常。
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
這個方法,目測是modCount的主要用途,是的!看這個demo
public class LinkedListDemo { public static void main(String[] args) { LinkedList<Integer> list = new LinkedList<Integer>(); list.add(2); ListIterator<Integer> iterator = list.listIterator(); while (iterator.hasNext()) { list.add(33); Integer integer = iterator.next(); } } }
這個demo將會拋出ConcurrentModificationException異常。好吧,爲何要拋異常?好吧,這裏做者不想咱們在用迭代器的時候還經過容器實例操做容器(我yy的),誰知道會發生什麼事情呢?
因此,在使用迭代器時,要個人經驗是:不要在迭代器裏面再經過該容器實例操做容器
到這裏,Iterator/ListIterator方法告一段落
clone方法
/** * Returns a shallow copy of this {@code LinkedList}. (The elements * themselves are not cloned.) * * @return a shallow copy of this {@code LinkedList} instance */ public Object clone() { LinkedList<E> clone = superClone(); // Put clone into "virgin" state clone.first = clone.last = null; clone.size = 0; clone.modCount = 0; // Initialize clone with our elements for (Node<E> x = first; x != null; x = x.next) clone.add(x.item); return clone; } @SuppressWarnings("unchecked") private LinkedList<E> superClone() { try { return (LinkedList<E>) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } }
由註釋知道了,這個clone方法是淺拷貝(shallow copy)。先經過superClone拷貝,而後將first,last,size,modCount都給初始化成默認狀態,而後調用鏈表的add方法添加各個元素。
序列化,反序列化
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out any hidden serialization magic s.defaultWriteObject(); // Write out size s.writeInt(size); // Write out all elements in the proper order. for (Node<E> x = first; x != null; x = x.next) s.writeObject(x.item); } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic s.defaultReadObject(); // Read in size int size = s.readInt(); // Read in all elements in the proper order. for (int i = 0; i < size; i++) linkLast((E)s.readObject()); }
LinkedList沒有用默認的序列化,而是本身實現的自定義序列化反序列化方法。
注意:writeObject()與readObject()都是private方法,那麼它們是如何被調用的呢?毫無疑問,是使用反射。
總結:
在寫本文時,沒有徹底分析LinkedList的增刪改,我以爲這部分都是上大學時數據結構學過的內容。相反,一些其餘內容,好比clone深淺拷貝,序列化倒是咱們常常忽略的內容。還有iterator的用法,說真的,平時也不怎麼用,有時在iterator上踩幾個坑也是有可能的。