LinkedList源码

LinkedList层次结构

在这里插入图片描述
如图所示,LinkedList继承了AbstractSequentialList,实现了List, Deque, Cloneable, java.io.Serializable接口。

AbstractSequentialList:
这是一个抽象类,继承了AbstractList类。而AbstractList类实现了List接口,所以AbstractSequentialList类主要作用是实现了List接口的大量实现,让LinkedList最大限度的减少不必要的实现的工作量。同时AbstractSequentialList有一个抽象方法:

public abstract ListIterator<E> listIterator(int index);

需要LinkedList将该抽象方法具体化。

List接口

因为AbstractList已经实现了List接口,LinkedList又实现了一遍,通过查阅资料得知这里是作者加上的,作者感觉会有用,但是实际没有影响。具体的网址:http://stackoverflow.com/questions/2165204/why-does-linkedhashsete-extend-hashsete-and-implement-sete(参考博客:https://www.cnblogs.com/zhangyinhua/p/7687377.html)。

Deque接口:
Deque接口是双端队列的称呼。实现了Deque接口,LinkedList就变成了双端链表,可以实现在头部或者尾部插入或者删除元素。

LinkedList属性

链表容量:

transient int size = 0;

链表的头节点:

transient Node<E> first;

链表的尾节点:

transient Node<E> last;

LinkedList构造方法

无参构造函数:

    /**
     * Constructs an empty list.
     */
    public LinkedList() {
    }

带参构造函数:

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

带参构造函数会构造一个包含参数集合的链表。

LinkedList常用的方法

add(E e)方法:
向链表尾部添加一个元素e
代码:

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

add()方法调用 linkLast(e)方法:

    /**
     * Links e as last element.
     */
    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++;
    }

linkLast(e)方法将元素e添加在链表的尾部,节点变量l保存当前节点的尾部节点,构造一个新的节点Node,构造函数Node<>(l, e, null)表示:l为节点e的前一个节点,e为当前节点,第三个参数表示新添加节点的下一个节点。因为是向尾部添加,所以新加节点的下一个节点(next)是null。 last = newNode;表示将链表的尾指针指向新构造的节点。如果l(尾节点)是空的,说明这个链表是空的,那么就将头节点指针也指向新加的节点。如果不是空链表,那么就想原来链表的尾指针,指向新的节点。然后链表容量加一,modCount表示对链表结构的修改次数。回到add(E e)方法,添加元素成功,返回true。

addLast(E e)方法:
像链表尾部添加一个元素e。和add(E e)方法一样,调用linkLast(e)方法。

    public void addLast(E e) {
        linkLast(e);
    }

addFirst(E e)方法:
向链表的头部添加新元素。

    public void addFirst(E e) {
        linkFirst(e);
    }

addFirst调用linkFirst方法。

    private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);
        first = newNode;
        if (f == null)
            last = newNode;
        else
            f.prev = newNode;
        size++;
        modCount++;
    }

节点f存储链表的头节点,构造新的节点newNode ,因为实在头部添加,所以构造函数的第一个参数是null,第三个参数表示新节点newNode 的下一个节点指针指向链表的原来的头节点。将链表的头指针指向新节点newNode。如果f(存储原链表的头节点)是空的,说明链表是空的,那么就将链表的尾指针也指向新加的节点newNode,否则将原来链表的头节点的前一元素指针指向新的节点newNode。链表容量加一,链表结构的修改次数加一。

remove(Object o)方法:
从该列表中删除指定元素的第一个匹配项(如果存在)。 如果此列表不包含该元素,则不会更改。

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

o表示要删除的元素,如果o是null。遍历链表,如果匹配到节点元素和o相同,调用unlink方法。

    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;
        size--;
        modCount++;
        return element;
    }

x为要删除的节点,element 表示x的存储的节点,next 表示x的后一节点,prev 表示x的前一节点。如果prev == null,即x为头节点,那么链表的头指针,就指向要删除节点的下一节点,即下一节点作为头节点。如果prev 不是null,即要删除的元素不是第一个,那么就将x的前一节点的next指针,指向要删除的节点的x的下一节点,即让x前节点和x的后一节点链接上,将x的前驱置为null。如果 next==null,即删除的是链表尾节点,这链表的尾指针last指向x(要删除的节点)的前驱。如果next 不是null,则让x的后驱节点的前驱指向x的前驱节点,即让x的后驱和x的前驱链接起来,然后将x的后驱置空。将x的元素置空,方便于垃圾回收。链表容量减一,记录修改链表结构的变量modCount加一。返回删除的元素。
返回到remove(Object o)方法,删除成功返回true。如果删除的不是null元素,同样遍历一遍链表,找到先匹配的元素后,调用unlink方法。

removeFirst()方法
删除并返回链表的第一个元素。

    public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
    }

如果链表是空链表,抛出异常。否则调用unlinkFirst方法。

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

将头节点f的元素置空,便于垃圾回收。f的后驱置空。使之与链表断开连接。然后让链表的头指针指向f的后驱节点。如果f的后驱节点是空的,即链表只有一个节点,那么让链表的尾节点置空,否则,就将f的后驱的前驱置空,即让f的后驱变为头节点。容量减一,修改链表结构的变量加一。返回被删除的元素。

listIterator(int index)方法:

    public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }

返回链表的迭代器,这个迭代器是快速失败的,也就是说如果在创建Iterator之后的任何时候对列表进行结构修改,除了通过list-iterator自己的remove或addmethods之外,list-iterator将抛出ConcurrentModificationException异常。

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

检查索引的范围,如果超出链表范围,抛出异常。
如过没有超出范围,则返回迭代器。
其他方法
因为继承了队列,所以LinkedList还有pop(),push(E e)方法,可以作为栈使用。
offer()和add()区别:add()向队列添加元素会检查队列容量,如果容量不够这抛出异常,offer的方法向队列添加元素,如果容量不够,会直接返回false。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值