LinkedList(jdk1.8)源碼分析

概述

LinkedList實現了List接口,在之前使用ArrayList的地方可以替換成LinkedList直接使用。與ArrayList相比,LinkedList(沒有實現RandomAccess接口)底層使用鏈表實現數據的存儲,鏈表相對於數組,在查找獲取方面不能直接通過索引獲取,只能遍歷獲取,速度較慢。但相對於數組實現的ArrayList在插入和刪除數據的時候,不存在容量擴容,也不需要數據的copy平移,速度上ArrayList快。
LinkedList 實現了Deque接口,Deque爲一個雙端隊列接口,定義了隊列,雙端隊列,棧操作的相關方法。也就是LinkedList可以用作隊列,和棧容器。

類繼承關係圖:

這裏寫圖片描述
LinkedList 實現了Iterable接口,說明該類可以通過迭代器遍歷他。
LinkedList 實現了Collection接口,說明該類具有集合常規方法操作。
LinkedList 實現了List接口,說明該類具有線性表操作方法。
LinkedList實現了Queue/Deque接口,說明該類可以用作棧,隊列,和雙端隊列。
LinkedList實現了Cloneable接口,說明該類具有clone方法。
LinkedList實現了Serializable接口,說明該類可以進行序列化。

成員變量:

//容器中元素個數
transient int size = 0;
//鏈表頭部節點(指針)
transient Node<E> first;
//鏈表尾部節點(指針)
transient Node<E> last;

節點內部類:

 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;
        }
    }

構造方法:

 //默認構造方法,構造一個空的LinkedList
    public LinkedList() {
    }

 //構造一個包含指定集合元素的LinkedList
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

List接口相關方法:

新增元素

 //在鏈表尾部加入一個元素
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
  //在鏈表尾部加入一個node元素
    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;  //鏈表容量爲空的時候加入一個元素 //first==last==newNode
        else
            l.next = newNode;//鏈表不爲空,則直接鏈接到last元素後邊
        //容量加一
        size++;
        //修改modCount 用於迭代器遍歷
        modCount++;
    }
   //在鏈表指定接點加入一個node元素
    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;//succ前節點爲空,則將first節點賦值newNode
        else
            pred.next = newNode;//succ前節點不爲空則直接將新加節點鏈接到前節點的後繼節點
        size++;//容量加一
        modCount++;//修改modCount 用於迭代器遍歷
    }
    //指定添加一個元素
    public void add(int index, E element) {
    //校驗index是否越界
        checkPositionIndex(index);
        if (index == size)
            linkLast(element);//index爲最後一個元素,鏈接到鏈表尾部
        else
            linkBefore(element, node(index));//index不爲最後一個元素,則將新元素鏈接到該指定位置
    }
    //校驗索引是否越界,越界拋出異常
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    //判斷索引位置是否合法
    boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }
//添加指定集合中的元素到LinkedList
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }
//具體的添加指定集合元素方法
    public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);//校驗是否越界
        //集合轉化爲數組
        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;
        if (index == size) {//最後一個節點
            succ = null;
            pred = last;
        } else {//不是最後一個節點
            succ = node(index);
            pred = succ.prev;
        }
//遍歷數組並插入到鏈表相應位置
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            //生成新元素節點類
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;//從鏈表頭部加入集合元素
            else
                pred.next = newNode;//依次加入新增元素
            pred = newNode;//pred指向當前最新節點元素
        }

        if (succ == null) {//index插入位置爲鏈表尾部則last指向最後一個新增元素節點
            last = pred;
        } else {//index插入位置爲鏈表其他位置,則pred後繼節點指向斷開節點
            pred.next = succ;
            succ.prev = pred; 斷開節點前繼節點指向添加元素位置
        }

        size += numNew;//LinkedList數量增加numNew 
        modCount++;//修改modCount 用於迭代器遍歷
        return true;
    }

刪除元素

//刪除指定元素
 public boolean remove(Object o) {
 //LinkedList允許元素爲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;
    }
    //從鏈表中移除某個節點
    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;//移除節點爲鏈表頭部,則頭節點直接指向next節點
        } else {
            prev.next = next;//移除節點不爲鏈表頭部,則移除節點的前繼節點的後繼節點指向next節點
            x.prev = null;//將移除節點的前繼節點置NULL
        }
        //處理移除節點的後繼節點
        if (next == null) {//移除節點爲鏈表尾部,則將尾部節點直接指向移除節點的前繼節點
            last = prev;
        } else {//移除節點不爲鏈表尾部,則移除節點的後繼節點的前繼節點指向移除節點的後繼節點
            next.prev = prev;
            x.next = null;//將移除節點的後繼節點置NULL
        }
        //移除節點數據端置NULL便於垃圾回收
        x.item = null;
        size--;//數量減一
        modCount++;//修改modCount值
        return element;
    }
    //清空LinkedList
   public void clear() {
       //從頭節點遍歷置空節點
        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;//LinkedList大小置空
        modCount++;//修改modCount值
    }

查找元素

  //獲取指定位置元素
    public E get(int index) {
    //校驗索引是否合法
        checkElementIndex(index);
        //調用node方法獲取元素數據
        return node(index).item;
    }
   //檢驗索引是否在合理範圍,不合理拋出IndexOutOfBoundsException異常
   private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    //真正校驗索引範圍
    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }
  //獲取指定索引位置節點方法
    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;
        }
    }

修改元素

//修改指定位置元素
 public E set(int index, E element) {
        //校驗索引位置是否合法
        checkElementIndex(index);
        //獲取指定索引節點
        Node<E> x = node(index);
        //節點數據賦值
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }

迭代器

  //獲取指定範圍的迭代器,且可以正向和反向迭代遍歷
    public ListIterator<E> listIterator(int index) {
    //校驗索引是否在合法範圍
        checkPositionIndex(index);
        return new ListItr(index);
    }
//新版本迭代器內部類
    private class ListItr implements ListIterator<E> {
    //迭代遍歷返回的當前臨時節點(next方法中使用,用於緩存當前節點),初始值爲null,迭代器迭代遍歷開始後指向容器當前節點值。
        private Node<E> lastReturned;
        //當前節點 next方法調用後指向下一個節點
        private Node<E> next;
        //當前節點的索引值,next方法調用後指向下一個節點索引值,用於判斷是否還有數據
        private int nextIndex;
        //迭代器遍歷時候判斷容器是否發生過變化
        private int expectedModCount = modCount;
//指定索引位置的構造方法
        ListItr(int index) {
            // assert isPositionIndex(index);
            //index==size 則next爲空,表示迭代器處於遍歷結束狀態,否則等於node方法返回值,node方法內部有index越界判斷,越界則拋出異常
            next = (index == size) ? null : node(index);
            //當前節點索引值,next方法調用後指向下一個節點索引值
            nextIndex = index;
        }
//判斷正向遍歷是否還有元素
        public boolean hasNext() {
            return nextIndex < size;
        }
//正向迭代遍歷取值
        public E next() {
        //校驗LinkedList是否修改過 若修改過拋出異常
            checkForComodification();
            //若正向遍歷沒有值則拋異常
            if (!hasNext())
                throw new NoSuchElementException();
//緩存當前節點引用,用於節點元素值返回
            lastReturned = next;
            //next節點指向下個節點
            next = next.next;
            //nextIndex索引指向下個節點索引
            nextIndex++;
            //返回當前節點數據元素
            return lastReturned.item;
        }
//是否可以進行前向迭代
        public boolean hasPrevious() {
            return nextIndex > 0;
        }
//前向遍歷取值
        public E previous() {
         //校驗LinkedList是否修改過,若修改過拋出異常
            checkForComodification();
            //若前向遍歷無值,拋出異常
            if (!hasPrevious())
                throw new NoSuchElementException();
//緩存當前節點引用,用於節點元素值返回。此外對next賦值next的前驅節點,若next==null,
//則賦值當前容器的尾部節點(本人分析代碼邏輯不會賦值尾部節點)
            lastReturned = next = (next == null) ? last : next.prev;
            //nextIndex索引指向前向節點索引
            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);
            //處理迭代器狀態(next==lastReturned邏輯,比較繞,發現調用next方法後,再調用previous方法,會出現此種邏輯,兩者反向調用也會出現此種情況),
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;//移除當前節點後,lastRetunrned置空,垃圾回收
            expectedModCount++;//修改容器狀態變化標誌,標識容器發生了變化
        }
//通過迭代器更新元素
        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            //直接賦值
            lastReturned.item = e;
        }
//通過迭代器新增元素
        public void add(E e) {
        //校驗容器狀態發生變化
            checkForComodification();
            //當前返回節點值置空
            lastReturned = null;
            //此處邏輯和LinkedList容器新增邏輯相同
            if (next == null)
                linkLast(e);//當前遍歷器處於鏈表尾部,直接向鏈表尾部插入數據
            else
                linkBefore(e, next);//迭代器處於鏈表其他位置,則向指定節點前插入新節點
            nextIndex++;//迭代器索引指向next所指向數據
            expectedModCount++;//修改容器變化狀態標誌,標識容器發生了變化
        }
//jdk1.8新加 jdk lambda表達式
        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();
        }
//校驗LinkedList是否發生變化(新增元素,刪除元素)
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

   //獲取老版本迭代器
    public Iterator<E> descendingIterator() {
        return new DescendingIterator();
    }

 //兼容1.6之前版本的老版本迭代器 該迭代器,就是對新迭代器的包裝,只能進行正向遍歷
    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();
        }
    }

其它方法

//鏈表轉化爲數組
    public Object[] toArray() {
    //new 一個新數組
        Object[] result = new Object[size];
        int i = 0;
        //遍歷將數據copy到數組
        for (Node<E> x = first; x != null; x = x.next)
            result[i++] = x.item;
        return result;
    }
//序列化標誌Id
    private static final long serialVersionUID = 876323262645176354L;
  //自定義序列化方法
    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());
    }

棧操作接口方法

//元素進棧方法
    public void push(E e) {
        addFirst(e);
    }
//在鏈表頭部加入新節點
    public void addFirst(E e) {
        linkFirst(e);
    }

 //真正鏈表頭部加入節點方法
    private void linkFirst(E e) {
        final Node<E> f = first;
        //構造新加入元素節點,新節點後繼節點指向f節點,前繼節點爲null
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
       //當容器爲空的時候,last尾部節點==first==newNode
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;//之前的頭結點的前繼節點指向新加入節點
        size++;//修改容器當前數量
        modCount++;//累加容器修改狀態值
    }
 //元素出棧方法
    public E pop() {
        return removeFirst();
    }
   //從鏈表頭部取頭節點
    public E removeFirst() {
        final Node<E> f = first;
        //當頭節點爲空也就是容器爲空的時候,拋出異常
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(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
        //頭節點指向next節點
        first = next;
        if (next == null)
            last = null;//最後一個元素出棧,會走此邏輯
        else
            next.prev = null;//前繼節點置空
            //(first節點的前繼節點都爲空)
        size--;//容量減一
        modCount++;//累加,容器修改狀態
        return element;//返回出棧元素
    }

隊列操作接口方法

//向隊列中加入元素
    public boolean offer(E e) {
    //內部調用add方法
        return add(e);
    }
    //向隊列加入元素此爲list接口定義方法
     public boolean add(E e) {
      //在鏈表尾部加入一個元素
        linkLast(e);
        return true;
    }
 //在鏈表尾部加入一個元素
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
  //在鏈表尾部加入一個node元素
    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;  //鏈表容量爲空的時候加入一個元素 //first==last==newNode
        else
            l.next = newNode;//鏈表不爲空,則直接鏈接到last元素後邊
        //容量加一
        size++;
        //修改modCount 用於迭代器遍歷
        modCount++;
    }

//從隊列頭部獲取一個元素,並移除,當隊列爲空會拋出異常
   public E remove() {
  //內部調用removeFirst
        return removeFirst();
    }
    //移除鏈表第一個節點
    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(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;
    }
 //該函數和remove函數功能基本一致,只是當隊列爲空,返回null值
  public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
//從隊列中獲取第一個元素,但不移除該元素,當隊列爲空返回null值
    public E peek() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
//從隊列中獲取第一個元素,但不移除該元素,當隊列爲空拋出異常
    public E element() {
        return getFirst();
    }
 //真正的獲取第一個元素
      public E getFirst() {
        final Node<E> f = first;
        //隊列會空拋出異常
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }

雙端隊列接口方法

 //向雙端隊列中頭部加入一個元素
public void addFirst(E e) {
        linkFirst(e);//鏈表頭部加入節點
   }
//向雙端隊列尾部加入一個元素
 public void addLast(E e) {
        linkLast(e);//鏈表尾部加入節點
    }
 //向雙端隊列中頭部加入一個元素,和Addfirst方法一樣只是加入了返回值
 public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }
 //向雙端隊列中頭部加入一個元素,和addLast方法一樣只是加入了返回值
 public boolean offerLast(E e) {
        addLast(e);
        return true;
    }
 //從雙端隊列頭部獲取一個元素並移除該元素,當隊列爲空拋出異常
  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);
    }
//從雙端隊列頭部獲取一個元素,並移除該元素,當隊列爲空返回null
  public E pollFirst() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
//從雙端隊列尾部獲取一個元素,並移除該元素,當隊列爲空返回null
  public E pollLast() {
        final Node<E> l = last;
        return (l == null) ? null : unlinkLast(l);
    }
//從隊列頭部獲取元素,不移除該元素,隊列爲空拋出異常
   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;
    }
//從隊列頭部獲取元素,不移除該元素,隊列爲空返回NULL
    public E peekFirst() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
     }
//從隊列尾部部獲取元素,不移除該元素,隊列爲空返回NULL
    public E peekLast() {
        final Node<E> l = last;
        return (l == null) ? null : l.item;
    }

從雙端隊列中移除某個元素,正向向遍歷鏈表刪除
public boolean removeFirstOccurrence(Object o) {
        return remove(o);
    }

//從雙端隊列中移除某個元素,反向遍歷鏈表刪除
  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;
    }

總結:

LinkedList底層由雙向鏈表實現,可以輕鬆實現數據插入,和刪除(比數組實現的ArrayList 效率高),不需要擴容,但查找訪問效率比數組慢。
LinkedList實現了List接口,在使用ArrayList的地方可以替換使用。
LinkedList實現了Deque接口,可以用作隊列,棧,雙端隊列。
LinkedList 不支持多線程,通過迭代器遍歷的時候,如果有其他線程刪除或新增元素,會拋出 ConcurrentModificationException()異常。
LinkedList 遍歷刪除元素,最好通過迭代器實現。LinkedList有兩種迭代器,一種只能單向迭代,最新的一種可以雙向,並且指定迭代範圍。
LinkedList實現了自己的序列化方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章