1. 程式人生 > >LinkedList原始碼解析 基於Node結構

LinkedList原始碼解析 基於Node結構

先來看看LinkedList的定義

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  • 1
  • 2
  • 3

AbstractSequentialList繼承了AbstractList並實現了一些方法,其他與ArrayList基本一致就不寫了,現在說下Deque這個介面

public interface Deque<E> extends Queue
<E> {
//隊頭插入元素 void addFirst(E e); //隊尾插入元素 void addLast(E e); //隊頭插入元素返回是否成功 boolean offerFirst(E e); //隊尾插入元素返回是否成功 boolean offerLast(E e); //刪除頭頂元素(當linkedlist為空時丟擲異常) E removeFirst(); //刪除尾部元素(當linkedlist為空時丟擲異常) E removeLast(); //刪除頭頂元素(當linkedlist為空時返回null)
E pollFirst(); //刪除尾部元素(當linkedlist為空時返回null) E pollLast(); //獲得頭頂元素(當linkedlist為空時丟擲異常) E getFirst(); //獲得尾部元素(當linkedlist為空時丟擲異常) E getLast(); //獲得頭頂元素(當linkedlist為空時返回null) E peekFirst(); //獲得尾部元素(當linkedlist為空時返回null) E peekLast(); //刪除最後一次出現的元素o boolean removeLastOccurrence(Object o); //相當於addLast
boolean add(E e); //相當於add boolean offer(E e); //刪除頭部元素,如果沒有可刪除的丟擲異常 E remove(); //獲取並移除此佇列的頭,如果此佇列為空,則返回 null E poll(); //獲取,但是不移除此佇列的頭。此方法與 peek 唯一的不同在於:此佇列為空時將丟擲一個異常 E element(); //獲取但不移除此佇列的頭;如果此佇列為空,則返回 null E peek(); //相當於addFirst void push(E e); //相當於removeFirst() E pop(); //移除指定的元素 boolean remove(Object o); //是否包含指定的元素 boolean contains(Object o); //獲得元素數 public int size(); //獲得迭代器 Iterator<E> iterator(); //獲得逆向的迭代器 Iterator<E> descendingIterator(); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
3.屬性
  • 1

記住LinkedList是基於雙向迴圈連結串列設計的

transient int size = 0;
//第一個元素
transient Node<E> first;
//最後一個元素
transient Node<E> last;
//內部類Node
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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
4.構造器
  • 1
//建立一個空linkedlist
public LinkedList() {
}
//根據傳入的list集合建立一個linkedlist
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
5.解析部分方法原始碼 

5.1 增加方法
  • 1
  • 2
  • 3
public boolean add(E e) {
  linkLast(e);
    return true;
}
void linkLast(E e) {
    //把最後一個元素複製給l
    final Node<E> l = last;
    //根據傳入物件建立一個新的node元素
    final Node<E> newNode = new Node<>(l, e, null);
    //把這個node賦值最後一個元素
    last = newNode;
    //如果還沒插入之前last是null,把first也賦值為newnode
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}
//下面看看另外一種插入指定位置的add方法
public void add(int index, E element) {
    //檢查輸入的index符不符合要求
    checkPositionIndex(index);
    //如果傳入index剛好在隊尾,相當於直接呼叫add()方法
    if (index == size)
        linkLast(element);
    else
        //呼叫方法插入
        linkBefore(element, node(index));
}
//先來看看node方法怎麼查詢對應的node元素
Node<E> node(int index) {
    //二分查詢法提高查詢速度,如果index小於size的一半,或者大於一半
    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;
    }
}
//現在來看看linkBefore方法
void linkBefore(E e, Node<E> succ) {
    // 把元素插入的index對應的元素之前
    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++;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
5.2 刪除方法
  • 1
//remove方法是刪除頂部元素,裡面呼叫了另外的方法
public E remove() {
    return removeFirst();
}
//現在我們來看看呼叫的方法內部是怎麼寫的
public E removeFirst() {
    //裡面寫的很簡單,最主要的還是unlinkFirst方法
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}
//再來看看unlinkFirst方法的內部
private E unlinkFirst(Node<E> f) {
    // 把對應的元素賦值為null
    final E element = f.item;
    final Node<E> next = f.next;
    f.item = null;
    // 讓垃圾回收儘快處理掉這個物件
    f.next = null; 
    first = next;
    if (next == null)
        last = null;
    else
        next.prev = null;
    size--;
    modCount++;
    return element;
}
//以下兩個方法最後都是呼叫了unlink方法
public E remove(int index) {
    //檢查index是否符合要求的方法
    checkElementIndex(index);
    return unlink(node(index));
}
public boolean remove(Object 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) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}
//現在來看看unlink方法
E unlink(Node<E> x) {
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;
    // 把傳入nude的與上一個node之間的關係清空
    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }
    // 把傳入nude的與下一個node之間的關係清空
    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }
    // 把自己賦值為空,能夠更快的垃圾回收
    x.item = null;
    size--;
    modCount++;
    return element;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
5.3 修改方法
  • 1
public E set(int index, E element) {
    //檢查index是否符合要求
    checkElementIndex(index);
    //獲得傳入index對應的node
    Node<E> x = node(index);
    //獲得修改之前的值
    E oldVal = x.item;
    //把當前元素賦值為傳入的值
    x.item = element;
    //返回修改之前的值
    return oldVal;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
5.4 查詢方法
  • 1
//有兩種查詢方法,一種只是獲得元素,一種是獲得元素並且刪除元素
//先來看看獲得元素方法,很簡單呼叫了上面講的node方法
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}
//另外一種是獲得元素並且刪除的方法,也很簡單呼叫了上面的刪除方法,刪除方法會返回元素
public E poll() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
5.5 迭代器
  • 1
//迭代器也分為兩種,一種是正常順序迭代,一種是逆向迭代
//先來看看正常順序迭代的方法,可以看到是呼叫了自己的一個內部類
public Iterator<E> iterator() {
    return listIterator();
}
public ListIterator<E> listIterator() {
    return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
    //看名字就知道是個檢查index是否符合要求的方法
    rangeCheckForAdd(index);
    return new ListItr(index);
}
//下面來詳細看看ListItr這個類內部是怎麼寫的
//方法比較簡單,就不多寫註釋了
private class ListItr implements ListIterator<E> {
    //最後一次返回的元素
    private Node<E> lastReturned = null;
    //下一個元素
    private Node<E> next;
    //下一個指標
    private int nextIndex;
    //期待改變次數,保證迭代過程中沒有做修改
    private int expectedModCount = modCount;

    ListItr(int 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++;
    }

    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

//再來看看逆向迭代的方法,也是建立了一個內部類返回
public Iterator<E> descendingIterator() {
    return new DescendingIterator();
}
//老樣子,來看看內部類的原始碼,很簡單next方法直接呼叫了itr的previous方法
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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

End!