1. 程式人生 > >List源碼解析之LinkedList 源碼分析

List源碼解析之LinkedList 源碼分析

返回 move 構造函數 assert 性能 雙向循環鏈表 return 線程不安全 包含

LinkedList簡介

實現了List和Deque接口,既可以看作一個順序容器,又可以看作一個隊列(Queue),同時又可以看作一個棧(Stack)(處理棧和隊列問題,首選ArrayDeque,它的性能比LinkedList作棧和隊列使用好很多)。
LinkedList是一種雙向鏈表,通過firstlast引用分別指向鏈表的第一個和最後一個元素。
LinkedList是非線程安全的,也就是說它不是同步的,適合單線程環境使用;需要多個線程並發訪問,可以先采用Collections.synchronizedList()方法對其進行包裝。
LinkedList實現了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實現了Cloneable接口,能被克隆。

屬性和構造函數

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; } } /** * Constructs an empty list. */ public LinkedList() { } /** * 構造一個包含指定collection 的元素的列表,這些元素按照 * 該collection 的叠代器返回它們的順序排列的 */ public LinkedList(Collection<? extends E> c) { this(); addAll(c); }

存儲

set(int index, E element)

// 用指定的元素替代此列表中指定位置上的元素,並返回以前位於該位置上的元素  
public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }

add(E e)

// 添加指定元素到鏈表尾部,花費時間為常數時間
public boolean add(E e) {
  linkLast(e);
  return true;
}

/**
 * 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++;
}

add(int index, E element)

// 在指定位置插入
public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
}

// 下標位置越界檢查
private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
      throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

  /**
   * Inserts element e before non-null Node succ.
   */
  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++;
  }

addAll(Collection<? extends E> c)

// 按照指定collection 的叠代器所返回的元素順序,將該collection 中的所有元素添加到此列表的尾部
public boolean addAll(Collection<? extends E> c) {
  return addAll(size, c);
}

// 具體看源碼吧

讀取

get(int index)

// 返回指定下標的元素
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

刪除

1.先找到要刪除元素的引用,2.修改相關引用,完成刪除操作

remove(int index)

使用下標計數

// 刪除指定位置的元素,並返回
public E remove(int index) {
  checkElementIndex(index); // 檢查下標是否越界
  return unlink(node(index));
}

    /**
     * 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; //let GC work
        size--;
        modCount++;
        return element;
    }

remove(Object o)

使用equales方法

// 刪除指定元素
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;
}

增刪元素的時候,只需改變指針,不需要像數組那樣對整體數據進行移動、復制等消耗性能的操作。

遍歷

遍歷的時候耗時,for循環(無窮大) > ForEach > 叠代器,優先使用叠代器方式。

```java
for(Iterator it = list.iterator();it.hasNext();){}

```

隊列操作

E peek()

// 獲取第一個元素
public E peek() {
  final Node<E> f = first;
  return (f == null) ? null : f.item;
}

E peekFirst()

// 獲取第一個元素,同E peek() 
public E peekFirst() {
  final Node<E> f = first;
  return (f == null) ? null : f.item;
}

E peekLast()

// 獲取最後一個元素
public E peekLast() {
  final Node<E> l = last;
  return (l == null) ? null : l.item;
}

E pop()

// 移除第一個元素並返回
public E pop() {
  return removeFirst();
}

E pollFirst()

// 移除第一個元素,同E pop()
public E pollFirst() {
  final Node<E> f = first;
  return (f == null) ? null : unlinkFirst(f);
}

E pollLast()

// 移除最後一個元素
public E pollLast() {
  final Node<E> l = last;
  return (l == null) ? null : unlinkLast(l);
}

push(E e)

// 隊首添加一個元素
public void push(E e) {
  addFirst(e);
}

總結

  1. 基於雙向循環鏈表實現,不存在容量不足的問題,沒有擴容的方法
  2. 增刪元素快,查找慢
  3. 元素排列有序,可重復,可為null
  4. 實現了棧和隊列的操作方法,因此也可以作為棧、隊列和雙端隊列來使用。
  5. 非同步,線程不安全

參考

  • pzxwhc
  • 蘭亭風雨
  • JCFInternals

======華麗麗的分隔線======
作者:jimzhang
出處:http://www.jianshu.com/p/9d223d28eadb
版權所有,歡迎保留原文鏈接進行轉載:)

List源碼解析之LinkedList 源碼分析