LinkedList源码解读(JDK1.8)

220 阅读3分钟

上一篇中解读了一下开发中最常用到的ArrayList在jdk1.7 和1.8中的不同,以及了解扩容机制,严格上来说,两个版本没有很大的改动,本文将接着对Linked List进行解读。

先看Linked List继承关系图谱


通过知识图谱,可以看到LinkedList是继承了AbstractSequentiaList,实现了List  、Deque Cloneable 、Serializable 等接口。


继承AbstractSequentiaList:

实现List:说明ArrayList是存取有序,可以有重复元素,且元素可以是为null值;

实现Deque:说明ArrayList同时也具备队列的特性:

实现Cloneable:说明支持拷贝,且是浅拷贝;

实现Serializable:说明可以实现序列化。

全局变量


构造函数


对构造函数进一步解读

     //无参构造方法
    public LinkedList() {
    }
     //通过一个集合初始化LinkedList,元素顺序有这个集合的迭代器返回顺序决定
    public LinkedList(Collection<? extends E> c) {
        // 调用无参构造函数
        this();
        // 添加集合中所有的元素
        addAll(c);
    } 

由于LinkedList底层是链表结构,在扩容时候非常方便,这于数据结构密切相关,接着再看;


  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 boolean add(E e) {
        // 通过调用尾插法来插入指定元素
        linkLast(e);
        return true;
    } 
       void linkLast(E e) {
//            得到最后一个节点
            final Node<E> l = last;
//            将前驱节点位置,元素,后继节点为null作为参数新生一个节点
            final Node<E> newNode = new Node<>(l, e, null);
//            最后一个节点
            last = newNode;
//            如果最后节点是null ,那么第一个节点是新节点;如果不是null,下一个节点是新节点
            if (l == null)
                first = newNode;
            else
                l.next = newNode;
//            长度加1
            size++;
            modCount++;
        }

指定索引位置添加元素



 public void add(int index, E element) {
        // 判断指定位置是否合法
        checkPositionIndex(index);
        // 如果指定位置在尾部,则通过尾插法来插入指定元素
        if (index == size)
            linkLast(element);
        else        
        //如果指定位置不是尾部,则添加到指定位置前
            linkBefore(element, node(index));
    } 
     // 判断指定位置是否合法
    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }
     //检查索引位置
     private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
     //判断插入元素时指定位置是否合法
    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

ArrayList list =new LinkedList();
list.add(1);//当第一次add时候,将Node节点的信息设置为,前驱为null,存储元素数据,后驱节点保留

添加元素的思路:

首先创建一个Node节点,同时将节点的前驱和后继分别设置为前一个节点的后继和null,如果是指定位置插入,则将前驱节点保存为指定位置前节点,后继节点保存为指定位置后节点的前驱。