成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Java集合之LinkedList源碼解析

DC_er / 2941人閱讀

摘要:快速失敗在用迭代器遍歷一個(gè)集合對(duì)象時(shí),如果遍歷過(guò)程中對(duì)集合對(duì)象的內(nèi)容進(jìn)行了修改增加刪除修改,則會(huì)拋出。原理由于迭代時(shí)是對(duì)原集合的拷貝進(jìn)行遍歷,所以在遍歷過(guò)程中對(duì)原集合所作的修改并不能被迭代器檢測(cè)到,所以不會(huì)觸發(fā)。

原文地址

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中Node節(jié)點(diǎn)的定義,Node類(lèi)是LinkedList的靜態(tài)內(nèi)部類(lèi)。

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

    Node(Node prev, E element, Node 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 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 f = first;//得到首節(jié)點(diǎn)
    final Node 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 l = last; //得到尾節(jié)點(diǎn)
    final Node 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 succ) {
    final Node pred = succ.prev;//獲取前一個(gè)節(jié)點(diǎn)
    final Node 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 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 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 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 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的添加步驟:

創(chuàng)建newNode節(jié)點(diǎn),將newNode的后繼指針指向succ,前驅(qū)指針指向pred

將succ的前驅(qū)指針指向newNode

根據(jù)pred是否為null,進(jìn)行不同操作。

如果pred為null,說(shuō)明該節(jié)點(diǎn)插入在頭節(jié)點(diǎn)之前,要重置first頭節(jié)點(diǎn)

如果pred不為null,那么直接將pred的后繼指針指向newNode即可

addAll的添加步驟:

檢查index索引范圍

得到集合數(shù)據(jù)

得到插入位置的前驅(qū)和后繼節(jié)點(diǎn)

遍歷數(shù)據(jù),將數(shù)據(jù)插入到指定位置

刪除元素

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

// 刪除首節(jié)點(diǎn)并返回刪除前首節(jié)點(diǎn)的值,內(nèi)部使用 (f == first && f != null)
private E unlinkFirst(Node f) {
    final E element = f.item;      // 獲取首節(jié)點(diǎn)的值 
    final Node 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 l) {
    final E element = l.item;//獲取尾節(jié)點(diǎn)的值
    final Node 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 x) {
    //獲取當(dāng)前值和前后節(jié)點(diǎn)
    final E element = x.item;
    final Node next = x.next;
    final Node 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 f = first;//得到第一個(gè)節(jié)點(diǎn)
    if (f == null)          //如果為空,拋出異常
        throw new NoSuchElementException();
    return unlinkFirst(f);
}
//刪除最后一個(gè)元素并返回刪除的值
public E removeLast() {
    final Node 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 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 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 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 f = first;
    return (f == null) ? null : f.item;
 }
//出隊(duì)(從后端),獲得最后一個(gè)元素,不存在會(huì)返回null,不會(huì)刪除元素(節(jié)點(diǎn))
public E peekLast() {
    final Node l = last;
    return (l == null) ? null : l.item;
}
//出隊(duì)(從前端),獲得第一個(gè)元素,不存在會(huì)返回null,會(huì)刪除元素(節(jié)點(diǎn))
public E pollFirst() {
    final Node f = first;
    return (f == null) ? null : unlinkFirst(f);
}
//出隊(duì)(從后端),獲得最后一個(gè)元素,不存在會(huì)返回null,會(huì)刪除元素(節(jié)點(diǎn))
public E pollLast() {
    final Node l = last;
    return (l == null) ? null : unlinkLast(l);
}
//入棧,從前面添加
public void push(E e) {
    addFirst(e);
}
//出棧,返回棧頂元素,從前面移除(會(huì)刪除)
public E pop() {
    return removeFirst();
}
迭代器
//返回迭代器
public Iterator descendingIterator() {
    return new DescendingIterator();
}
//迭代器
private class DescendingIterator implements Iterator {
    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 listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
}

private class ListItr implements ListIterator {
    private Node lastReturned;
    private Node 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 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 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事件。

快速失?。╢ail—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ì)拋出。因此,不能依賴(lài)于這個(gè)異常是否拋出而進(jìn)行并發(fā)操作的編程,這個(gè)異常只建議用于檢測(cè)并發(fā)修改的bug。

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

安全失?。╢ail—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 f = first;//得到首節(jié)點(diǎn)
    if (f == null)          //如果為空,拋出異常
        throw new NoSuchElementException();
    return f.item;
}
//獲取最后一個(gè)元素
public E getLast() {
    final Node 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 x = first; x != null; ) {
        Node 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 x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

//獲取指定位置的節(jié)點(diǎn)
Node node(int index) {
    if (index < (size >> 1)) {//如果位置索引小于列表長(zhǎng)度的一半(或一半減一),從前面開(kāi)始遍歷;
        Node 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 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 x = first; x != null; x = x.next) {
            if (x.item == null)
                return index;
            index++;
        }
    } else {
        for (Node 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 x = last; x != null; x = x.prev) {
            index--;
            if (x.item == null)
                return index;
        }
    } else {
        for (Node x = last; x != null; x = x.prev) {
            index--;
            if (o.equals(x.item))
                return index;
        }
    }
    return -1;
}

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

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

    for (Node 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 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[] 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 x = first; x != null; x = x.next)
        result[i++] = x.item;

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

    return a;
}

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69570.html

相關(guān)文章

  • java源碼

    摘要:集合源碼解析回歸基礎(chǔ),集合源碼解析系列,持續(xù)更新和源碼分析與是兩個(gè)常用的操作字符串的類(lèi)。這里我們從源碼看下不同狀態(tài)都是怎么處理的。 Java 集合深入理解:ArrayList 回歸基礎(chǔ),Java 集合深入理解系列,持續(xù)更新~ JVM 源碼分析之 System.currentTimeMillis 及 nanoTime 原理詳解 JVM 源碼分析之 System.currentTimeMi...

    Freeman 評(píng)論0 收藏0
  • 我的阿里路+Java面經(jīng)考點(diǎn)

    摘要:我的是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)。因?yàn)槲倚睦砗芮宄?,我的目?biāo)是阿里。所以在收到阿里之后的那晚,我重新規(guī)劃了接下來(lái)的學(xué)習(xí)計(jì)劃,將我的短期目標(biāo)更新成拿下阿里轉(zhuǎn)正。 我的2017是忙碌的一年,從年初備戰(zhàn)實(shí)習(xí)春招,年三十都在死磕JDK源碼,三月份經(jīng)歷了阿里五次面試,四月順利收到實(shí)習(xí)offer。然后五月懷著忐忑的心情開(kāi)始了螞蟻金...

    姘擱『 評(píng)論0 收藏0
  • List集合就這么簡(jiǎn)單【源碼剖析】

    摘要:線程不安全底層數(shù)據(jù)結(jié)構(gòu)是鏈表。的默認(rèn)初始化容量是,每次擴(kuò)容時(shí)候增加原先容量的一半,也就是變?yōu)樵瓉?lái)的倍刪除元素時(shí)不會(huì)減少容量,若希望減少容量則調(diào)用它不是線程安全的。 前言 聲明,本文用得是jdk1.8 前一篇已經(jīng)講了Collection的總覽:Collection總覽,介紹了一些基礎(chǔ)知識(shí)。 現(xiàn)在這篇主要講List集合的三個(gè)子類(lèi): ArrayList 底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組。線程不安全 ...

    cpupro 評(píng)論0 收藏0
  • Java集合問(wèn)題大匯總

    摘要:集合中成員很豐富,常用的集合有,,等。實(shí)現(xiàn)接口的集合主要有。集合中不能包含重復(fù)的元素,每個(gè)元素必須是唯一的。而以作為實(shí)現(xiàn)的構(gòu)造函數(shù)的訪問(wèn)權(quán)限是默認(rèn)訪問(wèn)權(quán)限,即包內(nèi)訪問(wèn)權(quán)限。與接口不同,它是由一系列鍵值對(duì)組成的集合,提供了到的映射。 原文地址 Java集合 Java集合框架:是一種工具類(lèi),就像是一個(gè)容器可以存儲(chǔ)任意數(shù)量的具有共同屬性的對(duì)象。 Java集合中成員很豐富,常用的集合有Arra...

    894974231 評(píng)論0 收藏0
  • 類(lèi)的加載機(jī)制 - 收藏集 - 掘金

    摘要:是現(xiàn)在廣泛流行的代從開(kāi)始學(xué)習(xí)系列之向提交代碼掘金讀完本文大概需要分鐘。為了進(jìn)行高效的垃圾回收,虛擬機(jī)把堆內(nèi)存劃分成新生代老年代和永久代中無(wú)永久代,使用實(shí)現(xiàn)三塊區(qū)域。 React Native 開(kāi)源項(xiàng)目 - 仿美團(tuán)客戶(hù)端 (Android、iOS 雙適配) - Android - 掘金推薦 React Native 學(xué)習(xí)好項(xiàng)目,仿照美團(tuán)客戶(hù)端... 極簡(jiǎn) GitHub 上手教程 - 工具...

    Gilbertat 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<