LinkedList源码分析

简介: Java中List是一个必须要掌握的基础知识,List是一个接口,实现List接口的基础类有很多,其中最具有代表性的两个:ArrayList和LinkedList。

Java中List是一个必须要掌握的基础知识,List是一个接口,实现List接口的基础类有很多,其中最具有代表性的两个:ArrayList和LinkedList。


01变量


今天主要讲解一下LinkedList的基本数据接口和源码分析。LinkedList的底层则是链表的结构,它可以进行高效的插入和移除的操作,基于一个双向链表的结构。源码变量定义可以看到:


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;



02图结构


用一个图理解一下:LinkedList的Node节点结构

565a552761e902d9ae5c607a7ba84acf_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

prev是存储的上一个节点的引用。

element是存储的具体的内容。

next是存储的下一个节点的引用。

LinkedList的整体结构图

911404c2068986887f544e3641e8132f_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png


从图解中可以看出,有好多的Node,并且还有first和last这两个变量保存头部和尾部节点的信息。

还有就是它不是一个循环的双向链表,因为他前后都是null,这个也是我们需要注意的地方。


03常用方法


3.1 构造方法:


/**  * Constructs an empty list.  */  public LinkedList() {  //无参构造方法 }
  /**  * Constructs a list containing the elements of the specified  * collection, in the order they are returned by the collection's  * iterator.  *  * @param  c the collection whose elements are to be placed into this list  * @throws NullPointerException if the specified collection is null  */  public LinkedList(Collection<? extends E> c) {  //以集合c形式,把所有元素插入链表中  this();  addAll(c);  }


3.2 添加元素方法:


/**   * Appends the specified element to the end of this list.   *   * <p>This method is equivalent to {@link #addLast}.   *   * @param e element to be appended to this list   * @return {@code true} (as specified by {@link Collection#add})   */   public boolean add(E e) {      linkLast(e);      return true;   }


/** * 将集合插入到链表的尾部 */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;    //如果新增元素为0,则不添加,并且返回false    if (numNew == 0)        return false;
    //定义index节点的前置节点,后置节点    Node<E> pred, succ;
    //判断是不是链表的尾部,如果是,那么就在链表尾部追加数据    //尾部的后置节点一定是null,前置节点是队尾    if (index == size) {        succ = null;        pred = last;    } else {
        //如果不是在链表的末尾而是在中间位置的话,        //取出index节点,作为后继节点        succ = node(index);
        //index节点的前节点,作为前驱的节点        pred = succ.prev;    }
    //链表批量的增加,去循环遍历原数组,依次去 插入节点的操作    for (Object o : a) {        @SuppressWarnings("unchecked")         //类型转换        E e = (E) o;        // 前置节点为pred,后置节点为null,当前节点值为e的节点newNode        Node<E> newNode = new Node<>(pred, e, null);        // 如果前置节点为空, 则newNode为头节点,否则为pred的next节点        if (pred == null)            first = newNode;        else            pred.next = newNode;        pred = newNode;    }    // 循环结束后,如果后置节点是null,说明此时是在队尾追加的    if (succ == null) {        last = pred;    } else {        //否则是在队中插入的节点 ,更新前置节点 后置节点        pred.next = succ;        succ.prev = pred;    }    // 修改数量size    size += numNew;    //修改modCount    modCount++;    return true;}


3.3 Node节点:


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

从上述Node节点源码可以看出,LinkedList的链表数据结构,是双向的每个元素既存储着上一个元素的引用又存储着下一个元素的引用。

addAll方法之后我们再看看其他的添加元素的方法,分为了头部addFist和尾部addLast。

addFist(E e)

将e元素添加到链表并且设置其为头节点Fist


public void addFirst(E e) {    linkFirst(e);}
/** * Links e as first element. * 将e元素弄成链接列表的第一个元素 */private void linkFirst(E e) {    final Node<E> f = first;
    //链表开头前驱为空,值为e,后继为f    final Node<E> newNode = new Node<>(null, e, f);    first = newNode;
    //若f为空,则表明列表中还没有元素,last也应该指向newNode    if (f == null)        last = newNode;    else        //否则,前first的前驱指向newNode        f.prev = newNode;    size++;    modCount++;}


3.4 Poll()方法:


/**     * Retrieves and removes the head (first element) of this list.     * 返回链表中第一个元素,如果链表是空,则返回空     * @return the head of this list, or {@code null} if this list is empty     * @since 1.5   */   public E poll() {      final Node<E> f = first;      return (f == null) ? null : unlinkFirst(f);   }


相关文章
|
1月前
|
调度 uml 索引
|
6月前
|
存储 Java 索引
每日一道面试题之ArrayList 和 LinkedList 的区别是什么?
每日一道面试题之ArrayList 和 LinkedList 的区别是什么?
|
3月前
面试题之:ArrayList和LinkedList有哪些区别
面试题之:ArrayList和LinkedList有哪些区别
|
5月前
|
存储 算法 Java
PriorityQueue 源码分析
这两个函数其实就是首先将其他集合转化为连续的array,再将其堆化。
34 0
|
8月前
|
存储 Java 索引
ArrayList源码分析
ArrayList源码分析
35 1
|
10月前
ArrayList与LinkedList获取指定元素对比(源码分析)
ArrayList与LinkedList获取指定元素对比(源码分析)
64 0
|
10月前
ArrayList与LinkedList移除指定元素对比(源码分析)
ArrayList与LinkedList移除指定元素对比(源码分析)
32 0
|
10月前
|
存储 Java 容器
一文带你进行ArrayList 源码分析
一文带你进行ArrayList 源码分析
10866 1
|
存储 索引
ArrayList与LinkedList区别源码分析
1、ArrayList是基于数组,LinkedList是基于链表 2、基于数组的ArrayList对于根据索引值查找比较高效;基于链表的LinkedList对于增加、删除操作比较高效 3、剖析CRUD:
188 0
|
存储 安全 Java
java集合系列(3)ArrayList(源码分析)
这篇文章开始介绍ArrayList。ArrayList基本上是我们在平时的开发当中,使用最多的一个集合类了,它是一个其容量能够动态增长的动态数组。所以这篇文章,旨在从源码的角度进行分析和理解。为了使得文章更加有条理,还是先给出这篇文章的大致脉络: 首先,ArrayList的基本介绍和源码API(只给出方法分析,重要的方法给出详细代码)。 然后,介绍遍历ArrayList的几种方式 接下来,叙述一下ArrayList与其他集合关键字的区别和优缺点 最后,进行一个总结
214 0
java集合系列(3)ArrayList(源码分析)