LinkedList

LinkedList是一個(gè)以雙向鏈表實(shí)現(xiàn)的List狂塘,它除了作為List使用,還可以作為隊(duì)列或者堆棧使用。

LinkedList介紹

LinkedList繼承關(guān)系

image

LinkedList簡介

  1. LinkedList是一個(gè)繼承于AbstractSequentialList的雙向鏈表。它也可以被當(dāng)做堆棧、隊(duì)列或雙端隊(duì)列進(jìn)行使用思杯。
  2. LinkedList實(shí)現(xiàn)List接口,能讓它進(jìn)行隊(duì)列操作。
  3. LinkedList實(shí)現(xiàn)Deque接口色乾,即能將LinkedList當(dāng)做雙端隊(duì)列使用誊册。
  4. LinkedList實(shí)現(xiàn)Cloneable,即覆蓋了函數(shù)clone()暖璧,能被克隆案怯。
  5. LinkedList實(shí)現(xiàn)了java.io.Serializable接口,這意味著LinkedList支持序列化澎办,能通過序列化去傳輸嘲碱。
  6. LinkedList中的操作不是線程安全的。

LinkedList源碼分析

AbstractSequentialList介紹

我們?cè)诳?code>LinkedList之前先簡單介紹下其父類AbstractSequentialList局蚀。

AbstractSequentialList繼承自AbstractList麦锯,是List接口的簡化版實(shí)現(xiàn)。

AbstractSequentialList只支持按次序訪問(鏈表在內(nèi)存中不是按順序存放的琅绅,而是通過指針連在一起扶欣,為了訪問某一元素,必須從鏈頭開始順著指針才能找到某一個(gè)元素千扶。)料祠,不像AbstractList可以隨機(jī)訪問。

想要實(shí)現(xiàn)一個(gè)支持次序訪問的List的話澎羞,只需要繼承這個(gè)類髓绽,并實(shí)現(xiàn)的指定的方法listIterator(int index)size()。實(shí)現(xiàn)ListIteratorhasNext()煤痕、next()梧宫、hasPrevious()接谨、previous()摆碉、previousIndex()就可以獲得一個(gè)不可修改的列表,如果你想讓它可修改還需實(shí)現(xiàn)remove()脓豪、set(E e)巷帝、add(E e)方法。

屬性

LinkedList的主要屬性如下代碼所示:

//鏈表節(jié)點(diǎn)的個(gè)數(shù)
transient int size = 0;
//鏈表首節(jié)點(diǎn)
transient Node<E> first;
//鏈表尾節(jié)點(diǎn)
transient Node<E> last;

關(guān)于transient關(guān)鍵字的最用可以查看我上次寫的ArrayList扫夜。

    //內(nèi)部靜態(tài)類
    private static class Node<E> {
        //當(dāng)前節(jié)點(diǎn)元素值
        E item;
        //下一個(gè)節(jié)點(diǎn)
        Node<E> next;
        //上一個(gè)節(jié)點(diǎn)
        Node<E> prev;

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

構(gòu)造函數(shù)

無參構(gòu)造函數(shù)

如果不傳入?yún)?shù)楞泼,則使用默認(rèn)構(gòu)造方法創(chuàng)建LinkedList對(duì)象,如下:

    public LinkedList() {
    }

此時(shí)創(chuàng)建的是一個(gè)空的鏈表笤闯。

帶Collection對(duì)象的構(gòu)造函數(shù)

    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

首先會(huì)調(diào)用無參數(shù)的構(gòu)造方法堕阔,然后調(diào)用addAll方法將集合內(nèi)元素全部加入到鏈表中,addAll方法我們后面會(huì)詳細(xì)的分析颗味。

從上述的倆個(gè)構(gòu)造方法可以看出LinkedList是一個(gè)無界鏈表超陆,不存在容量不足的問題。

添加元素

LinkedList主要提供addFirst浦马、addLast时呀、add张漂、addAll等方法來實(shí)現(xiàn)元素的添加。下面我們一一來看:

//在鏈表首部添加元素
public void addFirst(E e) {
        linkFirst(e);
    }
    private void linkFirst(E e) {
        //將內(nèi)部保存的首節(jié)點(diǎn)點(diǎn)賦值給f
        final Node<E> f = first;
        //創(chuàng)建新節(jié)點(diǎn)谨娜,新節(jié)點(diǎn)的next節(jié)點(diǎn)是當(dāng)前的首節(jié)點(diǎn)
        final Node<E> newNode = new Node<>(null, e, f);
        //把新節(jié)點(diǎn)作為新的首節(jié)點(diǎn)
        first = newNode;
        //判斷是否是第一個(gè)添加的元素
        //如果是將新節(jié)點(diǎn)賦值給last
        //如果不是把原首節(jié)點(diǎn)的prev設(shè)置為新節(jié)點(diǎn)
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        //更新鏈表節(jié)點(diǎn)個(gè)數(shù)
        size++;
        //將集合修改次數(shù)加1
        modCount++;
    }
//在鏈表尾部添加元素
public void addLast(E e) {
        linkLast(e);
    }
    void linkLast(E e) {
        //將內(nèi)部保存的尾節(jié)點(diǎn)賦值給l
        final Node<E> l = last;
        //創(chuàng)建新節(jié)點(diǎn)航攒,新節(jié)點(diǎn)的prev節(jié)點(diǎn)是當(dāng)前的尾節(jié)點(diǎn)
        final Node<E> newNode = new Node<>(l, e, null);
        //把新節(jié)點(diǎn)作為新的尾節(jié)點(diǎn)
        last = newNode;
        //判斷是否是第一個(gè)添加的元素
        //如果是將新節(jié)點(diǎn)賦值給first
        //如果不是把原首節(jié)點(diǎn)的next設(shè)置為新節(jié)點(diǎn)
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        //更新鏈表節(jié)點(diǎn)個(gè)數(shù)
        size++;
        //將集合修改次數(shù)加1
        modCount++;
    }
    //該方法和addLast方差不多,因?yàn)槭菬o界的趴梢,所以添加元素總是會(huì)成功
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    //該方法和上面add方法的區(qū)別是漠畜,該方法可以指定位置插入元素
    public void add(int index, E element) {
        //判斷是否越界
        checkPositionIndex(index);
        //如果index等于鏈表節(jié)點(diǎn)個(gè)數(shù),就將元素添加到倆表尾部坞靶,否則調(diào)用linkBefore方法
        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }
    //獲取指定位置的節(jié)點(diǎn)
    Node<E> node(int index) {
        //如果index小于size的一半盆驹,就從首節(jié)點(diǎn)開始遍歷,一直獲取x的下一個(gè)節(jié)點(diǎn)
        //如果index大于或等于size的一半滩愁,就從尾節(jié)點(diǎn)開始遍歷躯喇,一直獲取x的上一個(gè)節(jié)點(diǎn)
        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;
        }
    }
 //將元素插入到指定節(jié)點(diǎn)前
    void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        //拿到succ的上一節(jié)點(diǎn)
        final Node<E> pred = succ.prev;
        //創(chuàng)建新節(jié)點(diǎn)
        final Node<E> newNode = new Node<>(pred, e, succ);
        //將新節(jié)點(diǎn)作為succ的上一節(jié)點(diǎn)
        succ.prev = newNode;
        //判斷succ是否是首節(jié)點(diǎn)
        //如果是將新節(jié)點(diǎn)作為新的首節(jié)點(diǎn)
        //如果不是將新節(jié)點(diǎn)作為pred的下一節(jié)點(diǎn)
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        //更新鏈表節(jié)點(diǎn)個(gè)數(shù)
        size++;
        //將集合修改次數(shù)加1
        modCount++;
    }
    //將集合內(nèi)的元素依次插入index位置后
    public boolean addAll(int index, Collection<? extends E> c) {
        //判斷是否越界
        checkPositionIndex(index);
        //將集合轉(zhuǎn)換為數(shù)組
        Object[] a = c.toArray();
        int numNew = a.length;
        //判斷數(shù)組長度是否為0,為0直接返回false
        if (numNew == 0)
            return false;
        //pred上一個(gè)節(jié)點(diǎn)硝枉,succ當(dāng)前節(jié)點(diǎn)
        Node<E> pred, succ;
        //判斷index位置是否等于鏈表元素個(gè)數(shù)
        //如果等于succ賦值為null廉丽,pred賦值為當(dāng)前鏈表尾節(jié)點(diǎn)last
        //如果不等于succ賦值為index位置的節(jié)點(diǎn),pred賦值為succ的上一個(gè)節(jié)點(diǎn)
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }
        //循環(huán)數(shù)組
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            //創(chuàng)建新節(jié)點(diǎn)
            Node<E> newNode = new Node<>(pred, e, null);
            //如果上一個(gè)節(jié)點(diǎn)為null妻味,把新節(jié)點(diǎn)作為新的首節(jié)點(diǎn)正压,否則pred的下一個(gè)節(jié)點(diǎn)為新節(jié)點(diǎn)
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            //把新節(jié)點(diǎn)賦值給上一個(gè)節(jié)點(diǎn)
            pred = newNode;
        }
        //如果index位置的節(jié)點(diǎn)為null,把pred作業(yè)尾節(jié)點(diǎn)
        //如果不為null责球,pred的下一節(jié)點(diǎn)為index位置的節(jié)點(diǎn)焦履,succ的上一節(jié)點(diǎn)為pred
        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }
        //更新鏈表節(jié)點(diǎn)個(gè)數(shù)
        size += numNew;
        //將集合修改次數(shù)加1
        modCount++;
        //因?yàn)槭菬o界的,所以添加元素總是會(huì)成功
        return true;
    }

看到上面這么多種方式添加元素雏逾,其實(shí)本質(zhì)只是三種方式嘉裤,在鏈表的首部、尾部栖博、中間位置添加元素屑宠。如下圖所示:

image

在鏈表首尾添加元素很高效,在中間添加元素比較低效仇让,首先要找到插入位置的節(jié)點(diǎn)典奉,在修改前后節(jié)點(diǎn)的指針。

刪除元素

LinkedList提供了remove丧叽、removeFirst卫玖、removeLast等方法刪除元素。

    public boolean remove(Object o) {
        //因?yàn)長inkedList允許存在null踊淳,所以需要進(jìn)行null判斷
        if (o == null) {
            //從首節(jié)點(diǎn)開始遍歷
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    //調(diào)用unlink方法刪除指定節(jié)點(diǎn)
                    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;
    }
    //刪除指定節(jié)點(diǎn)
    E unlink(Node<E> x) {
        //獲取x節(jié)點(diǎn)的元素假瞬,以及它上一個(gè)節(jié)點(diǎn),和下一個(gè)節(jié)點(diǎn)
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
        //如果x的上一個(gè)節(jié)點(diǎn)為null,說明是首節(jié)點(diǎn)笨触,將x的下一個(gè)節(jié)點(diǎn)設(shè)置為新的首節(jié)點(diǎn)
        //否則將x的上一節(jié)點(diǎn)設(shè)置為next懦傍,將x的上一節(jié)點(diǎn)設(shè)為null
        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }
        //如果x的下一節(jié)點(diǎn)為null,說明是尾節(jié)點(diǎn)芦劣,將x的上一節(jié)點(diǎn)設(shè)置新的尾節(jié)點(diǎn)
        //否則將x的上一節(jié)點(diǎn)設(shè)置x的上一節(jié)點(diǎn)粗俱,將x的下一節(jié)點(diǎn)設(shè)為null
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
        //將x節(jié)點(diǎn)的元素值設(shè)為null,等待垃圾收集器收集
        x.item = null;
        //鏈表節(jié)點(diǎn)個(gè)數(shù)減1
        size--;
        //將集合修改次數(shù)加1
        modCount++;
        //返回刪除節(jié)點(diǎn)的元素值
        return element;
    }
    //刪除指定位置的節(jié)點(diǎn)虚吟,其實(shí)和上面的方法差不多
    //通過node方法獲得指定位置的節(jié)點(diǎn)寸认,再通過unlink方法刪除
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
//刪除首節(jié)點(diǎn)
public E remove() {
        return removeFirst();
    }
    //刪除首節(jié)點(diǎn)
    public E removeFirst() {
        final Node<E> f = first;
        //如果首節(jié)點(diǎn)為null,說明是空鏈表串慰,拋出異常
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }
    //刪除首節(jié)點(diǎn)
    private E unlinkFirst(Node<E> f) {
        //首節(jié)點(diǎn)的元素值
        final E element = f.item;
        //首節(jié)點(diǎn)的下一節(jié)點(diǎn)
        final Node<E> next = f.next;
        //將首節(jié)點(diǎn)的元素值和下一節(jié)點(diǎn)設(shè)為null偏塞,等待垃圾收集器收集
        f.item = null;
        f.next = null; // help GC
        //將next設(shè)置為新的首節(jié)點(diǎn)
        first = next;
        //如果next為null,說明說明鏈表中只有一個(gè)節(jié)點(diǎn)邦鲫,把last也設(shè)為null
        //否則把next的上一節(jié)點(diǎn)設(shè)為null
        if (next == null)
            last = null;
        else
            next.prev = null;
        //鏈表節(jié)點(diǎn)個(gè)數(shù)減1
        size--;
        //將集合修改次數(shù)加1
        modCount++;
        //返回刪除節(jié)點(diǎn)的元素值
        return element;
    }
    //刪除尾節(jié)點(diǎn)
    public E removeLast() {
        final Node<E> l = last;
        //如果首節(jié)點(diǎn)為null灸叼,說明是空鏈表,拋出異常
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }
    private E unlinkLast(Node<E> l) {
        //尾節(jié)點(diǎn)的元素值
        final E element = l.item;
        //尾節(jié)點(diǎn)的上一節(jié)點(diǎn)
        final Node<E> prev = l.prev;
        //將尾節(jié)點(diǎn)的元素值和上一節(jié)點(diǎn)設(shè)為null庆捺,等待垃圾收集器收集
        l.item = null;
        l.prev = null; // help GC
        //將prev設(shè)置新的尾節(jié)點(diǎn)
        last = prev;
        //如果prev為null古今,說明說明鏈表中只有一個(gè)節(jié)點(diǎn),把first也設(shè)為null
        //否則把prev的下一節(jié)點(diǎn)設(shè)為null
        if (prev == null)
            first = null;
        else
            prev.next = null;
        //鏈表節(jié)點(diǎn)個(gè)數(shù)減1
        size--;
        //將集合修改次數(shù)加1
        modCount++;
        //返回刪除節(jié)點(diǎn)的元素值
        return element;
    }

刪除和添加一樣滔以,其實(shí)本質(zhì)只有三種方式捉腥,即刪除首部、尾部你画、中間節(jié)點(diǎn)抵碟。如下圖所示:

image

和添加一樣,首尾刪除很高效坏匪,刪除中間元素比較低效要先找到節(jié)點(diǎn)位置拟逮,再修改前后指針。

獲取元素

LinkedList提供了get剥槐、getFirst唱歧、getLast等方法獲取節(jié)點(diǎn)元素值宪摧。

    //獲取指定位置的元素值
    public E get(int index) {
        //判斷是否越界
        checkElementIndex(index);
        //直接調(diào)用node方法獲取指定位置的節(jié)點(diǎn)粒竖,并反回其元素值
        return node(index).item;
    }
    //獲取鏈表首節(jié)點(diǎn)的元素值
    public E getFirst() {
        final Node<E> f = first;
        //判斷是否是空鏈表,如果是拋出異常几于,否則直接返回首節(jié)點(diǎn)的元素值
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }
    //獲取鏈表尾節(jié)點(diǎn)的元素值
    public E getLast() {
        final Node<E> l = last;
        //判斷是否是空鏈表蕊苗,如果是拋出異常,否則直接返回尾節(jié)點(diǎn)的元素值
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
    }

更新指定位置節(jié)點(diǎn)的元素值

    public E set(int index, E element) {
        //判斷是否越界
        checkElementIndex(index);
        //指定位置的節(jié)點(diǎn)
        Node<E> x = node(index);
        E oldVal = x.item;
        //設(shè)置新值
        x.item = element;
        //返回老值
        return oldVal;
    }

關(guān)于隊(duì)列的操作

LinkedList可以作為FIFO(First In First Out)的隊(duì)列沿彭,也就是先進(jìn)先出的隊(duì)列使用朽砰,以下是關(guān)于隊(duì)列的操作。

    //獲取隊(duì)列的第一個(gè)元素,如果為null會(huì)返回null
    public E peek() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
    }
    //獲取隊(duì)列的第一個(gè)元素瞧柔,如果為null會(huì)拋出異常
    public E element() {
        return getFirst();
    }
    //獲取隊(duì)列的第一個(gè)元素漆弄,如果為null會(huì)返回null
    public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
    //獲取隊(duì)列的第一個(gè)元素,如果為null會(huì)拋出異常
    public E remove() {
        return removeFirst();
    }
    //將元素添加到隊(duì)列尾部
    public boolean offer(E e) {
        return add(e);
    }

關(guān)于雙端隊(duì)列的操作

雙端列隊(duì)可以作為棧使用造锅,棧的特性是LIFO(Last In First Out)撼唾,也就是后進(jìn)先出。所以作為棧使用也很簡單哥蔚,添加和刪除元素都只操作隊(duì)列的首節(jié)點(diǎn)即可倒谷。

    //將元素添加到首部
    public boolean offerFirst(E e) {
        addFirst(e);
        return true;
    }
    //將元素添加到尾部
    public boolean offerLast(E e) {
        addLast(e);
        return true;
    }
    //獲取首部的元素值
    public E peekFirst() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
     }
    //獲取尾部的元素值
    public E peekLast() {
        final Node<E> l = last;
        return (l == null) ? null : l.item;
    }
    //刪除首部,如果為null會(huì)返回null
    public E pollFirst() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }
    //刪除尾部糙箍,如果為null會(huì)返回null
    public E pollLast() {
        final Node<E> l = last;
        return (l == null) ? null : unlinkLast(l);
    }
    //將元素添加到首部
    public void push(E e) {
        addFirst(e);
    }
    //刪除首部渤愁,如果為null會(huì)拋出異常
    public E pop() {
        return removeFirst();
    }
    //刪除鏈表中元素值等于o的第一個(gè)節(jié)點(diǎn),其實(shí)和remove方法是一樣的深夯,因?yàn)閮?nèi)部還是調(diào)用的remove方法
    public boolean removeFirstOccurrence(Object o) {
        return remove(o);
    }

    //刪除鏈表中元素值等于o的最后一個(gè)節(jié)點(diǎn)
    public boolean removeLastOccurrence(Object o) {
        //因?yàn)長inkedList允許存在null抖格,所以需要進(jìn)行null判斷
        if (o == null) {
            //和remove方法的區(qū)別它是從尾節(jié)點(diǎn)往前遍歷
            for (Node<E> x = last; x != null; x = x.prev) {
                if (x.item == null) {
                    //調(diào)用unlink方法刪除指定節(jié)點(diǎn)
                    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;
    }

其他方法

    //判斷元素是否存在于鏈表中
    public boolean contains(Object o) {
        return indexOf(o) != -1;
    }
    
    //從前往后查找返回節(jié)點(diǎn)元素值等于o的位置,不存在返回-1
    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;
    }

    //該方法和上面indexOf方法相反咕晋,它是從后往前查找返回節(jié)點(diǎn)元素值等于o的位置他挎,不存在返回-1
    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;
    }

    //克隆函數(shù),返回LinkedList的克隆對(duì)象
    public Object clone() {
        LinkedList<E> clone = superClone();

        // 將新建LinkedList置于最初狀態(tài)
        clone.first = clone.last = null;
        clone.size = 0;
        clone.modCount = 0;

        // 將鏈表中所有節(jié)點(diǎn)的數(shù)據(jù)都添加到克隆對(duì)象中
        for (Node<E> x = first; x != null; x = x.next)
            clone.add(x.item);

        return clone;
    }

    //返回LinkedList節(jié)點(diǎn)單元素值的Object數(shù)組
    public Object[] toArray() {
        Object[] result = new Object[size];
        int i = 0;
        //將鏈表中所有節(jié)點(diǎn)的元素值添加到object數(shù)組中
        for (Node<E> x = first; x != null; x = x.next)
            result[i++] = x.item;
        return result;
    }

    // 返回LinkedList的模板數(shù)組捡需。所謂模板數(shù)組办桨,即可以將T設(shè)為任意的數(shù)據(jù)類型
    public <T> T[] toArray(T[] a) {
        //如果a的長度小于LinkedList節(jié)點(diǎn)個(gè)數(shù),說明a不能容納LinkedList的所有節(jié)點(diǎn)元素值
        //則新建一個(gè)數(shù)組站辉,數(shù)組大小為LinkedList節(jié)點(diǎn)個(gè)數(shù)呢撞,并賦值給a
        if (a.length < size)
            a = (T[])java.lang.reflect.Array.newInstance(
                                a.getClass().getComponentType(), size);
        int i = 0;
        Object[] result = a;
        // 將鏈表中所有節(jié)點(diǎn)的元素值都添加到數(shù)組a中
        for (Node<E> x = first; x != null; x = x.next)
            result[i++] = x.item;

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

        return a;
    }

    //將LinkedList中的數(shù)據(jù)寫入到輸入流中,先寫容量饰剥,再寫數(shù)據(jù)
    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);
    }

    //從輸入流中讀取數(shù)據(jù)殊霞,一樣是先讀容量,再讀數(shù)據(jù)
    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();
        //從輸入流中將元素值逐個(gè)添加到鏈表中
        // Read in all elements in the proper order.
        for (int i = 0; i < size; i++)
            linkLast((E)s.readObject());
    }

總結(jié)

  • LinkedList自己實(shí)現(xiàn)了序列化和反序列化汰蓉,因?yàn)樗鼘?shí)現(xiàn)了writeObject和readObject方法绷蹲。
  • LinkedList是一個(gè)以雙向鏈表實(shí)現(xiàn)的List。
  • LinkedList還是一個(gè)雙端隊(duì)列顾孽,具有隊(duì)列祝钢、雙端隊(duì)列、棧的特性若厚。
  • LinkedList在首部和尾部添加拦英、刪除元素效率高效,在中間添加测秸、刪除元素效率較低疤估。
  • LinkedList雖然實(shí)現(xiàn)了隨機(jī)訪問灾常,但是效率低效,不建議使用铃拇。
  • LinkedList是線程不安全的钞瀑。

文章作者: leisurexi

新博客地址: https://leisurexi.github.io

許可協(xié)議: 署名-非商業(yè)性使用-禁止演繹 4.0 國際 轉(zhuǎn)載請(qǐng)保留原文鏈接及作者。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末慷荔,一起剝皮案震驚了整個(gè)濱河市仔戈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拧廊,老刑警劉巖监徘,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吧碾,居然都是意外死亡凰盔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門倦春,熙熙樓的掌柜王于貴愁眉苦臉地迎上來户敬,“玉大人,你說我怎么就攤上這事睁本∧蚵” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵呢堰,是天一觀的道長抄瑟。 經(jīng)常有香客問我,道長枉疼,這世上最難降的妖魔是什么皮假? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮骂维,結(jié)果婚禮上惹资,老公的妹妹穿的比我還像新娘。我一直安慰自己航闺,他們只是感情好褪测,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潦刃,像睡著了一般侮措。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上福铅,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天萝毛,我揣著相機(jī)與錄音,去河邊找鬼滑黔。 笑死笆包,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的略荡。 我是一名探鬼主播庵佣,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼汛兜!你這毒婦竟也來了巴粪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤粥谬,失蹤者是張志新(化名)和其女友劉穎肛根,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漏策,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡派哲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了掺喻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芭届。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖感耙,靈堂內(nèi)的尸體忽然破棺而出褂乍,到底是詐尸還是另有隱情,我是刑警寧澤即硼,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布逃片,位于F島的核電站,受9級(jí)特大地震影響只酥,放射性物質(zhì)發(fā)生泄漏题诵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一层皱、第九天 我趴在偏房一處隱蔽的房頂上張望性锭。 院中可真熱鬧,春花似錦叫胖、人聲如沸草冈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怎棱。三九已至,卻和暖如春绷跑,著一層夾襖步出監(jiān)牢的瞬間拳恋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國打工砸捏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谬运,地道東北人隙赁。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像梆暖,于是被迫代替她去往敵國和親伞访。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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

  • 上一章進(jìn)行了ArrayList源碼分析轰驳,這一章分析一下另一個(gè)重要的List集合LinkedList厚掷。 Linked...
    wo883721閱讀 549評(píng)論 0 0
  • LinkedList 源碼分析 由于最近工作有點(diǎn)忙,進(jìn)行了 APP 的部分優(yōu)化级解,期間也學(xué)習(xí)了很多有關(guān)于布局優(yōu)化和其...
    醒著的碼者閱讀 650評(píng)論 1 6
  • LinkedList是一個(gè)實(shí)現(xiàn)了List接口和Deque接口的雙端鏈表冒黑。 其繼承關(guān)系如下圖 這里提到了雙端鏈表,到...
    SnowDragonYY閱讀 600評(píng)論 0 0
  • 準(zhǔn)備: LinkedList是基于鏈表(雙向循環(huán)鏈表)結(jié)構(gòu)的一種List勤哗,在分析LinkedList源碼之前我們先...
    先生_呂閱讀 350評(píng)論 0 3
  • LinkedList LinkedList是一種可以在任何位置進(jìn)行高效地插入和移除操作的有序序列抡爹,它是基于雙向鏈表...
    史路比閱讀 380評(píng)論 0 1