Linkedlist的源码分析

官方文档解释:

List和Deque接口的双向链表实现。 实现所有可选的列表操作,并允许所有元素(包括null )。
对于双向链表,所有操作都按预期执行。 索引到列表中的操作将从开始或结束遍历列表,以更接近指定索引的为准。
请注意,此实现不是同步的。 如果多个线程并发访问一个链表,并且至少有一个线程在结构上修改了链表,则必须进行外部同步。 (结构修改是添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)这通常是通过同步一些自然封装列表的对象来完成的。 如果不存在此类对象,则应使用Collections.synchronizedList方法“包装”该列表。 这最好在创建时完成,以防止对列表的意外不同步访问:
List list = Collections.synchronizedList(new LinkedList(...));
此类的iterator和listIterator方法返回的iterator是快速失败的:如果在创建迭代器后的任何时间以任何方式修改列表结构,除了通过 Iterator 自己的remove或add方法,迭代器将抛出ConcurrentModificationException 。 因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒着任意、非确定性行为的风险。
请注意,无法保证迭代器的快速失败行为,因为一般而言,在存在非同步并发修改的情况下不可能做出任何硬保证。 快速失败的迭代器会尽最大努力抛出ConcurrentModificationException 。 因此,编写一个依赖此异常来确保其正确性的程序是错误的:迭代器的快速失败行为应该仅用于检测错误。
此类是Java Collections Framework的成员。 

这个官方解释和ArrayList的有很多相似的地方,因此这两个List只是实现不一样,但是一些规定是基本上一样的

 

源码分析:

 

  transient int size = 0;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first; //指向第一个节点的指针

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    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;
        }
    }

 

节点的类型

 

 public LinkedList() {
    }

 

构造一个空的列表

 

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

按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表

 

public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

按照指定集合的​​迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾。 如果在操作进行时修改了指定的集合,则此操作的行为未定义。 (请注意,如果指定的集合是这个列表,并且它是非空的,则会发生这种情况。)

 

public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ; //succ指的是待添加节点 pred指的是待添加节点的前一个节点
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }

        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

        if (succ == null) {
            last = pred;
        } else {
            pred.next = succ;
            succ.prev = pred;
        }

        size += numNew;
        modCount++;
        return true;
    }

 

从指定位置开始,将指定集合中的所有元素插入此列表。 将当前在该位置的元素(如果有)和任何后续元素向右移动(增加它们的索引)。 新元素将按照指定集合的​​迭代器返回的顺序出现在列表中。

 

 Node<E> node(int index) {
        // assert isElementIndex(index);

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

 

 返回指定元素索引处的(非空)节点,此处对遍历进行了一个优化,不是盲目地从链头遍历到链尾,而是先判断更靠近哪一边,然后再进行遍历。

 

posted @ 2021-09-28 14:59  夏天·烟火·我的尸体  阅读(31)  评论(0)    收藏  举报