Java集合之LinkedList源碼解析

原文地址

LinkedList

  • 在Java.util包下
  • 繼承自AbstractSequentialList
  • 實(shí)現(xiàn) List 接口,能對(duì)它進(jìn)行隊(duì)列操作吼旧。
  • 實(shí)現(xiàn) Deque 接口惯雳,即能將LinkedList當(dāng)作雙端隊(duì)列使用畦幢。
  • 實(shí)現(xiàn)了Cloneable接口返奉,即覆蓋了函數(shù)clone()污尉,能克隆锐朴。
  • 實(shí)現(xiàn)java.io.Serializable接口酱酬,這意味著LinkedList支持序列化挑社,能通過(guò)序列化去傳輸吼肥。
  • 允許包含null值
  • 迭代器可以快速報(bào)錯(cuò)
  • 非線程安全的动猬,如果在多線程中使用(修改),需要在外部作同步處理。

LinkedList是一種可以在任何位置進(jìn)行高效地插入和移除操作的有序序列慈俯,它是基于雙向鏈表實(shí)現(xiàn)的刑峡。內(nèi)部有三個(gè)變量阳似,size表示鏈表中元素的個(gè)數(shù), first指向鏈表頭部玲献,last指向鏈表尾部眠砾。 結(jié)構(gòu)圖如下圖所示

LinkedList.png

下面是LinkedList中Node節(jié)點(diǎn)的定義,Node類是LinkedList的靜態(tài)內(nèi)部類淤井。

private static class Node<E> {
    E item;          // 當(dāng)前節(jié)點(diǎn)所存數(shù)據(jù)
    Node<E> next;    // 當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
    Node<E> prev;    // 當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

構(gòu)造方法(Construction method)

LinkedList提供了兩種種方式的構(gòu)造器,構(gòu)造一個(gè)空列表游两、以及構(gòu)造一個(gè)包含指定collection的元素的列表漩绵,
這些元素按照該collection的迭代器返回的順序排列的止吐。

public LinkedList() {
}

public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);   // 調(diào)用addAll方法,構(gòu)建一個(gè)包含指定集合c的列表
}

添加元素

因?yàn)長(zhǎng)inkedList即實(shí)現(xiàn)了List接口,又實(shí)現(xiàn)了Deque接口,所以LinkedList既可以添加將元素添加到尾部饭望,也可以將元素添加到指定索引位置,還可以添加添加整個(gè)集合雏节;另外既可以在頭部添加,又可以在尾部添加。

//添加元素作為第一個(gè)元素
public void addFirst(E e) {
    linkFirst(e);
}
//店家元素作為最后一個(gè)元素
public void addLast(E e) {
    linkLast(e);
}

//使用對(duì)應(yīng)參數(shù)作為第一個(gè)節(jié)點(diǎn),內(nèi)部使用
private void linkFirst(E e) {
    final Node<E> f = first;//得到首節(jié)點(diǎn)
    final Node<E> newNode = new Node<>(null, e, f);//創(chuàng)建一個(gè)節(jié)點(diǎn)
    first = newNode;        //更新首節(jié)點(diǎn)
    if (f == null)
        last = newNode;     //如果之前首節(jié)點(diǎn)為空(size==0)拓轻,那么尾節(jié)點(diǎn)就是首節(jié)點(diǎn)
    else
        f.prev = newNode;   //如果之前首節(jié)點(diǎn)不為空斯撮,之前的首節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)為當(dāng)前首節(jié)點(diǎn)
    size++;                 //長(zhǎng)度+1
    modCount++;             //修改次數(shù)+1
}
//使用對(duì)應(yīng)參數(shù)作為尾節(jié)點(diǎn)
void linkLast(E e) {
    final Node<E> l = last; //得到尾節(jié)點(diǎn)
    final Node<E> newNode = new Node<>(l, e, null);//使用參數(shù)創(chuàng)建一個(gè)節(jié)點(diǎn)
    last = newNode;         //設(shè)置尾節(jié)點(diǎn)
    if (l == null)
        first = newNode;    //如果之前尾節(jié)點(diǎn)為空(size==0),首節(jié)點(diǎn)即尾節(jié)點(diǎn)
    else
        l.next = newNode;   //如果之前尾節(jié)點(diǎn)不為空扶叉,之前的尾節(jié)點(diǎn)的后一個(gè)就是當(dāng)前的尾節(jié)點(diǎn)
    size++;
    modCount++;
}

//在非空節(jié)點(diǎn)succ之前插入元素E勿锅。
void linkBefore(E e, Node<E> succ) {
    final Node<E> pred = succ.prev;//獲取前一個(gè)節(jié)點(diǎn)
    final Node<E> newNode = new Node<>(pred, e, succ);//使用參數(shù)創(chuàng)建新的節(jié)點(diǎn)
    succ.prev = newNode;//當(dāng)前節(jié)點(diǎn)指向新的節(jié)點(diǎn)
    if (pred == null)
        first = newNode;//如果前一個(gè)節(jié)點(diǎn)為null,新的節(jié)點(diǎn)就是首節(jié)點(diǎn)
    else
        pred.next = newNode;//如果存在前節(jié)點(diǎn)枣氧,那么前節(jié)點(diǎn)的向后指向新節(jié)點(diǎn)
    size++;
    modCount++;
}

//添加指定集合的元素到列表溢十,默認(rèn)從最后開(kāi)始添加
public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);//size表示最后一個(gè)位置
}

/*
從指定位置(而不是下標(biāo)!下標(biāo)即索引從0開(kāi)始达吞,位置可以看做從1開(kāi)始张弛,其實(shí)也是0)后面添加指定集合的元素到列表中,只要有至少一次添加就會(huì)返回true
index換成position應(yīng)該會(huì)更好理解,所以也就是從索引為index(position)的元素的前面索引為index-1的后面添加吞鸭!
當(dāng)然位置可以為0啊寺董,為0的時(shí)候就是從位置0(雖然它不存在)后面開(kāi)始添加嘛,所以理所當(dāng)然就是添加到第一個(gè)位置(位置1的前面)的前面

比如列表:0 1 2 3刻剥,如果此處index=4(實(shí)際索引為3)遮咖,就是在元素3后面添加;如果index=3(實(shí)際索引為2)造虏,就在元素2后面添加御吞。
*/
public boolean addAll(int index, Collection<? extends E> c) {
    checkPositionIndex(index);  //檢查索引是否正確(0<=index<=size)
    Object[] a = c.toArray();   //得到元素?cái)?shù)組
    int numNew = a.length;      //得到元素個(gè)數(shù)
    if (numNew == 0)            //若沒(méi)有元素要添加,直接返回false
        return false;
    Node<E> pred, succ;
    if (index == size) {    //如果是在末尾開(kāi)始添加漓藕,當(dāng)前節(jié)點(diǎn)后一個(gè)節(jié)點(diǎn)初始化為null陶珠,前一個(gè)節(jié)點(diǎn)為尾節(jié)點(diǎn)
        succ = null;        //這里可以看做node(index),不過(guò)index=size了(index最大只能是size-1)享钞,所以這里的succ只能=null背率,也方便后面判斷
        pred = last;        
    } else {                //如果不是從末尾開(kāi)始添加,當(dāng)前位置的節(jié)點(diǎn)為指定位置的節(jié)點(diǎn)嫩与,前一個(gè)節(jié)點(diǎn)為要添加的節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)
        succ = node(index); //添加好元素后(整個(gè)新加的)的后一個(gè)節(jié)點(diǎn)
        pred = succ.prev;   
    }
    //遍歷數(shù)組并添加到列表中
    for (Object o : a) {
        @SuppressWarnings("unchecked") E e = (E) o;
        Node<E> newNode = new Node<>(pred, e, null);//創(chuàng)建一個(gè)節(jié)點(diǎn)寝姿,向前指向上面得到的前節(jié)點(diǎn)
        if (pred == null)
            first = newNode;    //若當(dāng)前節(jié)點(diǎn)為null,則新加的節(jié)點(diǎn)為首節(jié)點(diǎn)
        else
            pred.next = newNode;//如果存在前節(jié)點(diǎn)划滋,前節(jié)點(diǎn)會(huì)向后指向新加的節(jié)點(diǎn)
        pred = newNode;         //新加的節(jié)點(diǎn)成為前一個(gè)節(jié)點(diǎn)
    }
    if (succ == null) {
        //pred.next = null  //加上這句也可以更好的理解
        last = pred;        //如果是從最后開(kāi)始添加的饵筑,則最后添加的節(jié)點(diǎn)成為尾節(jié)點(diǎn)
    } else {
        pred.next = succ;   //如果不是從最后開(kāi)始添加的,則最后添加的節(jié)點(diǎn)向后指向之前得到的后續(xù)第一個(gè)節(jié)點(diǎn)
        succ.prev = pred;   //當(dāng)前处坪,后續(xù)的第一個(gè)節(jié)點(diǎn)也應(yīng)改為向前指向最后一個(gè)添加的節(jié)點(diǎn)
    }
    size += numNew;
    modCount++;
    return true;
}

//將指定的元素(E element)插入到列表的指定位置(index)
public void add(int index, E element) {
    checkPositionIndex(index); //index >= 0 && index <= size

    if (index == size) 
        linkLast(element); //尾插入
    else
        linkBefore(element, node(index));  //中間插入
}

linkBefore的添加步驟:

  1. 創(chuàng)建newNode節(jié)點(diǎn)根资,將newNode的后繼指針指向succ,前驅(qū)指針指向pred
  2. 將succ的前驅(qū)指針指向newNode
  3. 根據(jù)pred是否為null同窘,進(jìn)行不同操作玄帕。
  • 如果pred為null,說(shuō)明該節(jié)點(diǎn)插入在頭節(jié)點(diǎn)之前想邦,要重置first頭節(jié)點(diǎn)
  • 如果pred不為null裤纹,那么直接將pred的后繼指針指向newNode即可

addAll的添加步驟:

  1. 檢查index索引范圍
  2. 得到集合數(shù)據(jù)
  3. 得到插入位置的前驅(qū)和后繼節(jié)點(diǎn)
  4. 遍歷數(shù)據(jù),將數(shù)據(jù)插入到指定位置

刪除元素

同樣的LinkedList也提供了很多方法來(lái)刪除元素

// 刪除首節(jié)點(diǎn)并返回刪除前首節(jié)點(diǎn)的值丧没,內(nèi)部使用 (f == first && f != null)
private E unlinkFirst(Node<E> f) {
    final E element = f.item;      // 獲取首節(jié)點(diǎn)的值 
    final Node<E> next = f.next;   // 獲取首節(jié)點(diǎn)的后一個(gè)節(jié)點(diǎn)
    f.item = null;
    f.next = null; // help GC
    first = next;                 // 更新首節(jié)點(diǎn)
    if (next == null)             //如果不存在下一個(gè)節(jié)點(diǎn)鹰椒,則首尾都為null
        last = null;
    else
        next.prev = null;        //如果存在下一個(gè)節(jié)點(diǎn),那它的前指針為null
    size--;
    modCount++;
    return element;
}

// 刪除尾節(jié)點(diǎn)呕童,并返回尾節(jié)點(diǎn)的元素 (assert l == last && l != null)
private E unlinkLast(Node<E> l) {
    final E element = l.item;//獲取尾節(jié)點(diǎn)的值
    final Node<E> prev = l.prev;//獲取尾節(jié)點(diǎn)前一個(gè)節(jié)點(diǎn)
    l.item = null;
    l.prev = null;   // help GC
    last = prev;        //前一個(gè)節(jié)點(diǎn)成為新的尾節(jié)點(diǎn)
    if (prev == null)
        first = null;   //如果前一個(gè)節(jié)點(diǎn)不存在漆际,則首尾都為null
    else
        prev.next = null;//如果前一個(gè)節(jié)點(diǎn)存在,先后指向null
    size--;
    modCount++;
    return element;
}

// 刪除指定節(jié)點(diǎn)x并返回節(jié)點(diǎn)的值(x != null)
E unlink(Node<E> x) {
    //獲取當(dāng)前值和前后節(jié)點(diǎn)
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;
    if (prev == null) {
        first = next;   //如果前一個(gè)節(jié)點(diǎn)為空(如當(dāng)前節(jié)點(diǎn)為首節(jié)點(diǎn))夺饲,后一個(gè)節(jié)點(diǎn)成為新的首節(jié)點(diǎn)
    } else {
        prev.next = next;//如果前一個(gè)節(jié)點(diǎn)不為空奸汇,那么他先后指向當(dāng)前的下一個(gè)節(jié)點(diǎn)
        x.prev = null;  //help  GC
    }
    if (next == null) {
        last = prev;    //如果后一個(gè)節(jié)點(diǎn)為空(如當(dāng)前節(jié)點(diǎn)為尾節(jié)點(diǎn))施符,當(dāng)前節(jié)點(diǎn)前一個(gè)成為新的尾節(jié)點(diǎn)
    } else {
        next.prev = prev;//如果后一個(gè)節(jié)點(diǎn)不為空,后一個(gè)節(jié)點(diǎn)向前指向當(dāng)前的前一個(gè)節(jié)點(diǎn)
        x.next = null;  //help  GC
    }
    x.item = null;   //help  GC
    size--;
    modCount++;
    return element;
}

//刪除第一個(gè)元素并返回刪除的元素
public E removeFirst() {
    final Node<E> f = first;//得到第一個(gè)節(jié)點(diǎn)
    if (f == null)          //如果為空擂找,拋出異常
        throw new NoSuchElementException();
    return unlinkFirst(f);
}
//刪除最后一個(gè)元素并返回刪除的值
public E removeLast() {
    final Node<E> l = last;//得到最后一個(gè)節(jié)點(diǎn)
    if (l == null)          //如果為空操刀,拋出異常
        throw new NoSuchElementException();
    return unlinkLast(l);
}

序列化方法

private static final long serialVersionUID = 876323262645176354L;

//序列化:將linkedList的“大小,所有的元素值”都寫(xiě)入到輸出流中
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException {
    s.defaultWriteObject();
    s.writeInt(size);

    for (Node<E> x = first; x != null; x = x.next)
        s.writeObject(x.item);
}

//反序列化:先將LinkedList的“大小”讀出婴洼,然后將“所有的元素值”讀出
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    s.defaultReadObject();
    int size = s.readInt();

    for (int i = 0; i < size; i++)
        linkLast((E)s.readObject());  //以尾插入的方式
}

隊(duì)列操作

//提供普通隊(duì)列和雙向隊(duì)列的功能,當(dāng)然撼嗓,也可以實(shí)現(xiàn)棧柬采,F(xiàn)IFO,F(xiàn)ILO
//出隊(duì)(從前端)且警,獲得第一個(gè)元素粉捻,不存在會(huì)返回null,不會(huì)刪除元素(節(jié)點(diǎn))
public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}
//出隊(duì)(從前端)斑芜,不刪除元素肩刃,若為null會(huì)拋出異常而不是返回null
public E element() {
    return getFirst();
}
//出隊(duì)(從前端),如果不存在會(huì)返回null杏头,存在的話會(huì)返回值并移除這個(gè)元素(節(jié)點(diǎn))
public E poll() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}
//出隊(duì)(從前端)盈包,如果不存在會(huì)拋出異常而不是返回null,存在的話會(huì)返回值并移除這個(gè)元素(節(jié)點(diǎn))
public E remove() {
    return removeFirst();
}
//入隊(duì)(從后端)醇王,始終返回true
public boolean offer(E e) {
    return add(e);
}
//入隊(duì)(從前端)呢燥,始終返回true
public boolean offerFirst(E e) {
    addFirst(e);
    return true;
}
//入隊(duì)(從后端),始終返回true
public boolean offerLast(E e) {
    addLast(e);//linkLast(e)
    return true;
}
//出隊(duì)(從前端)寓娩,獲得第一個(gè)元素叛氨,不存在會(huì)返回null,不會(huì)刪除元素(節(jié)點(diǎn))
public E peekFirst() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
 }
//出隊(duì)(從后端)棘伴,獲得最后一個(gè)元素寞埠,不存在會(huì)返回null,不會(huì)刪除元素(節(jié)點(diǎn))
public E peekLast() {
    final Node<E> l = last;
    return (l == null) ? null : l.item;
}
//出隊(duì)(從前端)焊夸,獲得第一個(gè)元素仁连,不存在會(huì)返回null,會(huì)刪除元素(節(jié)點(diǎn))
public E pollFirst() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}
//出隊(duì)(從后端)阱穗,獲得最后一個(gè)元素怖糊,不存在會(huì)返回null,會(huì)刪除元素(節(jié)點(diǎn))
public E pollLast() {
    final Node<E> l = last;
    return (l == null) ? null : unlinkLast(l);
}
//入棧颇象,從前面添加
public void push(E e) {
    addFirst(e);
}
//出棧伍伤,返回棧頂元素,從前面移除(會(huì)刪除)
public E pop() {
    return removeFirst();
}

迭代器

//返回迭代器
public Iterator<E> descendingIterator() {
    return new DescendingIterator();
}
//迭代器
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 ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
}

private class ListItr implements ListIterator<E> {
    private Node<E> lastReturned;
    private Node<E> next;
    private int nextIndex;
    private int expectedModCount = modCount;//保存當(dāng)前modCount遣钳,確保fail-fast機(jī)制

    ListItr(int index) {
        next = (index == size) ? null : node(index);//得到當(dāng)前索引指向的next節(jié)點(diǎn)
        nextIndex = index;
    }

    public boolean hasNext() {   // 判斷后面是否還有元素
        return nextIndex < size;
    }
    
    public E next() {     //獲取下一個(gè)節(jié)點(diǎn)
        checkForComodification();
        if (!hasNext())
            throw new NoSuchElementException();

        lastReturned = next;
        next = next.next;
        nextIndex++;
        return lastReturned.item;
    }

    public boolean hasPrevious() {
        return nextIndex > 0;
    }

    //獲取前一個(gè)節(jié)點(diǎn)扰魂,將next節(jié)點(diǎn)向前移
    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++;
    }

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

在ListIterator的構(gòu)造器中,得到了當(dāng)前位置的節(jié)點(diǎn),就是變量next劝评。next()方法返回當(dāng)前節(jié)點(diǎn)的值并將next指向其后繼節(jié)點(diǎn)姐直,previous()方法返回當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)的值并將next節(jié)點(diǎn)指向其前驅(qū)節(jié)點(diǎn)。

由于Node是一個(gè)雙向節(jié)點(diǎn)蒋畜,所以這用了一個(gè)節(jié)點(diǎn)就可以實(shí)現(xiàn)從前向后迭代和從后向前迭代声畏。另外在ListIterator初始時(shí),exceptedModCount保存了當(dāng)前的modCount姻成,如果在迭代期間插龄,有操作改變了鏈表的底層結(jié)構(gòu),那么再操作迭代器的方法時(shí)將會(huì)拋出ConcurrentModificationException科展。

fail-fast

fail-fast 機(jī)制是java集合(Collection)中的一種錯(cuò)誤機(jī)制均牢。當(dāng)多個(gè)線程對(duì)同一個(gè)集合的內(nèi)容進(jìn)行操作時(shí),就可能會(huì)產(chǎn)生fail-fast事件才睹。例如:當(dāng)某一個(gè)線程A通過(guò)iterator去遍歷某集合的過(guò)程中徘跪,若該集合的內(nèi)容被其他線程所改變了;那么線程A訪問(wèn)集合時(shí)琅攘,就會(huì)拋出ConcurrentModificationException異常垮庐,產(chǎn)生fail-fast事件。

快速失斘肭佟(fail—fast)

在用迭代器遍歷一個(gè)集合對(duì)象時(shí)突硝,如果遍歷過(guò)程中對(duì)集合對(duì)象的內(nèi)容進(jìn)行了修改(增加、刪除置济、修改)解恰,則會(huì)拋出Concurrent Modification Exception。

原理:迭代器在遍歷時(shí)直接訪問(wèn)集合中的內(nèi)容浙于,并且在遍歷過(guò)程中使用一個(gè) modCount 變量护盈。集合在被遍歷期間如果內(nèi)容發(fā)生變化,就會(huì)改變modCount的值羞酗。每當(dāng)?shù)魇褂胔ashNext()/next()遍歷下一個(gè)元素之前腐宋,都會(huì)檢測(cè)modCount變量是否為expectedmodCount值,是的話就返回遍歷檀轨;否則拋出異常胸竞,終止遍歷。

注意:這里異常的拋出條件是檢測(cè)到 modCount参萄!=expectedmodCount 這個(gè)條件卫枝。如果集合發(fā)生變化時(shí)修改modCount值剛好又設(shè)置為了expectedmodCount值,則異常不會(huì)拋出讹挎。因此校赤,不能依賴于這個(gè)異常是否拋出而進(jìn)行并發(fā)操作的編程吆玖,這個(gè)異常只建議用于檢測(cè)并發(fā)修改的bug。

場(chǎng)景:java.util包下的集合類都是快速失敗的马篮,不能在多線程下發(fā)生并發(fā)修改(迭代過(guò)程中被修改)沾乘。

安全失敗(fail—safe)

采用安全失敗機(jī)制的集合容器浑测,在遍歷時(shí)不是直接在集合內(nèi)容上訪問(wèn)的翅阵,而是先復(fù)制原有集合內(nèi)容,在拷貝的集合上進(jìn)行遍歷迁央。

原理:由于迭代時(shí)是對(duì)原集合的拷貝進(jìn)行遍歷掷匠,所以在遍歷過(guò)程中對(duì)原集合所作的修改并不能被迭代器檢測(cè)到,所以不會(huì)觸發(fā)Concurrent Modification Exception漱贱。

缺點(diǎn):基于拷貝內(nèi)容的優(yōu)點(diǎn)是避免了Concurrent Modification Exception,但同樣地夭委,迭代器并不能訪問(wèn)到修改后的內(nèi)容幅狮,即:迭代器遍歷的是開(kāi)始遍歷那一刻拿到的集合拷貝,在遍歷期間原集合發(fā)生的修改迭代器是不知道的株灸。

場(chǎng)景:java.util.concurrent包下的容器都是安全失敗崇摄,可以在多線程下并發(fā)使用,并發(fā)修改慌烧。

其他方法

//獲取第一個(gè)元素
public E getFirst() {
    final Node<E> f = first;//得到首節(jié)點(diǎn)
    if (f == null)          //如果為空逐抑,拋出異常
        throw new NoSuchElementException();
    return f.item;
}
//獲取最后一個(gè)元素
public E getLast() {
    final Node<E> l = last;//得到尾節(jié)點(diǎn)
    if (l == null)          //如果為空,拋出異常
        throw new NoSuchElementException();
    return l.item;
}

//檢查是否包含某個(gè)元素屹蚊,返回bool
public boolean contains(Object o) {
    return indexOf(o) != -1;//返回指定元素的索引位置厕氨,不存在就返回-1,然后比較返回bool值
}
//返回列表長(zhǎng)度
public int size() {
    return size;
}

//清空表
public void clear() {     // help GC
    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;
    modCount++;
}
//獲取指定索引的節(jié)點(diǎn)的值
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}
//修改指定索引的值并返回之前的值
public E set(int index, E element) {
    checkElementIndex(index);    // 檢查下標(biāo)是否合法
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

//獲取指定位置的節(jié)點(diǎn)
Node<E> node(int index) {
    if (index < (size >> 1)) {//如果位置索引小于列表長(zhǎng)度的一半(或一半減一)汹粤,從前面開(kāi)始遍歷命斧;
        Node<E> x = first;//index==0時(shí)不會(huì)循環(huán),直接返回first
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {                 // 否則嘱兼,從后面開(kāi)始遍歷
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

//獲取指定元素從first開(kāi)始的索引位置国葬,不存在就返回-1
//這里不能按條件雙向找了,所以通常根據(jù)索引獲得元素的速度比通過(guò)元素獲得索引的速度快
public int indexOf(Object o) {
    int index = 0;
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            index++;
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item))
                return index;
            index++;
        }
    }
    return -1;
}
//獲取指定元素從first開(kāi)始最后出現(xiàn)的索引芹壕,不存在就返回-1
//但實(shí)際查找是從last開(kāi)始的
public int lastIndexOf(Object o) {
    int index = size;
    if (o == null) {
        for (Node<E> x = last; x != null; x = x.prev) {
            index--;
            if (x.item == null)
                return index;
        }
    } else {
        for (Node<E> x = last; x != null; x = x.prev) {
            index--;
            if (o.equals(x.item))
                return index;
        }
    }
    return -1;
}

//返回此 LinkedList實(shí)例的淺拷貝
public Object clone() {
    LinkedList<E> clone = superClone();

    clone.first = clone.last = null;
    clone.size = 0;
    clone.modCount = 0;

    for (Node<E> x = first; x != null; x = x.next)
        clone.add(x.item);

    return clone;
}

//返回一個(gè)包含LinkedList中所有元素值的數(shù)組
public Object[] toArray() {
    Object[] result = new Object[size];
    int i = 0;
    for (Node<E> x = first; x != null; x = x.next)
        result[i++] = x.item;
    return result;
}

//如果給定的參數(shù)數(shù)組長(zhǎng)度足夠汇四,則將ArrayList中所有元素按序存放于參數(shù)數(shù)組中,并返回
//如果給定的參數(shù)數(shù)組長(zhǎng)度小于LinkedList的長(zhǎng)度踢涌,則返回一個(gè)新分配的通孽、長(zhǎng)度等于LinkedList長(zhǎng)度的、包含LinkedList中所有元素的新數(shù)組
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        a = (T[])java.lang.reflect.Array.newInstance(
                            a.getClass().getComponentType(), size);
    int i = 0;
    Object[] result = a;
    for (Node<E> x = first; x != null; x = x.next)
        result[i++] = x.item;

    if (a.length > size)
        a[size] = null;

    return a;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末睁壁,一起剝皮案震驚了整個(gè)濱河市利虫,隨后出現(xiàn)的幾起案子挨厚,更是在濱河造成了極大的恐慌,老刑警劉巖糠惫,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疫剃,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡硼讽,警方通過(guò)查閱死者的電腦和手機(jī)巢价,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)固阁,“玉大人壤躲,你說(shuō)我怎么就攤上這事”溉迹” “怎么了碉克?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)并齐。 經(jīng)常有香客問(wèn)我漏麦,道長(zhǎng),這世上最難降的妖魔是什么况褪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任撕贞,我火速辦了婚禮,結(jié)果婚禮上测垛,老公的妹妹穿的比我還像新娘捏膨。我一直安慰自己,他們只是感情好食侮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布号涯。 她就那樣靜靜地躺著,像睡著了一般锯七。 火紅的嫁衣襯著肌膚如雪诚隙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天起胰,我揣著相機(jī)與錄音久又,去河邊找鬼。 笑死效五,一個(gè)胖子當(dāng)著我的面吹牛地消,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畏妖,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼脉执,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了戒劫?” 一聲冷哼從身側(cè)響起半夷,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤婆廊,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后巫橄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體淘邻,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年湘换,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宾舅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彩倚,死狀恐怖筹我,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帆离,我是刑警寧澤蔬蕊,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站哥谷,受9級(jí)特大地震影響岸夯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呼巷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一囱修、第九天 我趴在偏房一處隱蔽的房頂上張望赎瑰。 院中可真熱鬧王悍,春花似錦、人聲如沸餐曼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)源譬。三九已至集惋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間踩娘,已是汗流浹背刮刑。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留养渴,地道東北人雷绢。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像理卑,于是被迫代替她去往敵國(guó)和親翘紊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容