【Java集合框架源码分析(JDK1.7)】-LinkedList源码分析

LinkedList简介

  • LinkedList是一个双向链表。它继承了AbstractSequentialList,可以被当作堆栈、队列或双端队列操作
  • 实现了Lis能对它进行队列操作
  • 实现了Deque接口能将LinkedList当作双端队列使用。
  • LinkedList 实现了Cloneable接口可以被克隆。
  • LinkedList实现java.io.Serializable接口,因此它也支持序列化,能够通过序列化传输。
  • 与ArrayList一样不是同步的。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable

《【Java集合框架源码分析(JDK1.7)】-LinkedList源码分析》

  • 为什么继承AbstractSequentialList?

AbstractSequentialList中已经实现了get(int index)set(int index, E element)add(int index, E element)remove(int index)这些基本操作,LinkedList实现了List,也就相当于实现了get(int index)从而最大限度地减少了实现受“连续访问”数据存储(如链接列表)支持的此接口所需的工作,减少List实现复杂度。

LinkedList实现原理

  • 1.私有属性
    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;
  • 2.构造函数
    /** * 构造一个空列表 */
    public LinkedList() {
    }

    /** * 构造一个包含指定 collection 中的元素的列表,这些元素按其 collection 的迭代器返回的顺序排列 */
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }
  • 3.add(E e)

该方法是在链表的 end 添加元素,其调用了自己的方法 linkLast(E e)。
该方法首先将 last 的 Node 引用指向了一个新的 Node(l),然后根据l新建了一个 newNode,其中的元素就为要添加的 e;而后,我们让 last 指向了 newNode。接下来是自身进行维护该链表。


    /** * 在链表后面增加元素 */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    /** * 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++;
    }
  • 4.add(int index, E element)
    /** * 在指定 index 位置插入元素。如果 index 位置正好等于 size,则调用 linkLast(element) 将其插入末尾;否则调用 linkBefore(element, node(index))方法进行插入。 */
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

    void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }
  • 4.addAll(Collection
    /** * 添加指定 collection 中的所有元素到此列表的结尾,顺序是指定 collection 的迭代器返回这些元素的顺序。 */
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

    /** * 将collection中的数据从集合index位置开始插入 */
    public boolean addAll(int index, Collection<? extends E> c) {
        //检验将要插入index的位置是否合法
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        //若插入的元素为空,则返回false
        if (numNew == 0)
            return false;
         //succ用来保存index处的节点。插入位置如果是size,则在头结点前面插入,否则在获取index处的节点插入, pred用来获取前一个节点,插入时需要修改这个节点的next引用
        Node<E> pred, succ;
        if (index == size) {
            succ = null;
            pred = last;
        } else {
            succ = node(index);
            pred = succ.prev;
        }
        // 按顺序将a数组中的第一个元素插入到index处,将之后的元素插在这个元素后面
        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;
    }

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    /** * 二分法查找获取index处的节点,如果index大于size的一半,从后往前找;否则从前往后找 */
    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;
        }
    }
  • 5.获取元素
    /** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

ArrayList和LinkedList的区别:

  1. ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
  2. 对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
  3. 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

ArrayList和LinkedList是两个集合类,用于存储一系列的对象引用(references)。例如我们可以用ArrayList来存储一系列的String或者Integer。

参考:http://blog.csdn.net/ochangwen/article/details/50586260

    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/elricboa/article/details/78290642
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞