1 继承结构图

LinkedList是List的另一种实现。继承自AbstractSequentialList

2 数据结构

LinkedList与ArrayList不同的是LinkedList底层使用双向链表进行存储,其主要数据结构如下

  1.   // 记录List长度
  2.   transient int size = 0;
  3.  
  4.   // 指向LinkedList第一个节点
  5.   transient Node<E> first;
  6.  
  7.   // 指向LinkedList最后一个节点
  8.   transient Node<E> last;
  9.  
  10.   // Node Class如下
  11. private static class Node<E> {
  12. E item;
  13. Node<E> next;
  14. Node<E> prev;
  15.  
  16. Node(Node<E> prev, E element, Node<E> next) {
  17. this.item = element;
  18. this.next = next;
  19. this.prev = prev;
  20. }
  21. }

LinkedList的一个节点是一个Node对象,可以看到node.item记录值,并且分别有指向前一个节点和后一个节点的指针prev和next

3 构造方法

  1. public LinkedList() {}
  2.  
  3. public LinkedList(Collection<? extends E> c) {
  4. this();
  5. addAll(c);
  6. }

LinkedList也支持两种构造方式,无参构造和传入一个集合构造LinkedList,addAll的具体实现如下

  1. public boolean addAll(Collection<? extends E> c) {
  2. return addAll(size, c);
  3. }
  4.  
  5. public boolean addAll(int index, Collection<? extends E> c) {
  6. checkPositionIndex(index);
  7.  
  8. Object[] a = c.toArray();
  9. int numNew = a.length;
  10. if (numNew == 0)
  11. return false;
  12.  
  13. Node<E> pred, succ;
  14. if (index == size) {
  15. succ = null;
  16. pred = last;
  17. } else {
  18. succ = node(index);
  19. pred = succ.prev;
  20. }
  21.  
  22. for (Object o : a) {
  23. @SuppressWarnings("unchecked") E e = (E) o;
  24. Node<E> newNode = new Node<>(pred, e, null);
  25. if (pred == null)
  26. first = newNode;
  27. else
  28. pred.next = newNode;
  29. pred = newNode;
  30. }
  31.  
  32. if (succ == null) {
  33. last = pred;
  34. } else {
  35. pred.next = succ;
  36. succ.prev = pred;
  37. }
  38.  
  39. size += numNew;
  40. modCount++;
  41. return true;
  42. }

初始化是size=0,可见就是利用Collection的toArray方法把c转为对象数组,然后遍历新建Node,并逐个连起来,基本的链表操作。

4 一些方法介绍

  1. void linkBefore(E e, Node<E> succ) {
  2. // assert succ != null;
  3. final Node<E> pred = succ.prev;
  4. final Node<E> newNode = new Node<>(pred, e, succ);
  5. succ.prev = newNode;
  6. if (pred == null)
  7. first = newNode;
  8. else
  9. pred.next = newNode;
  10. size++;
  11. modCount++;
  12. }

linkBefore方法是在succ节点之前插入一个新的节点,其执行过程大致如下图

其他方法类似也都可以通过画图的形式了解大致执行步骤,涉及链表操作,画图能更好的理解执行过程,在此不再赘述。

5 与ArrayList的异同

ArrayList和LinkedList是List的两种实现,不同的ArrayList是基于动态数组的数据结构,而LinkedList是基于双向链表的数据结构。

他们的优缺点也正是由于他们所依赖的数据结构决定的

  • 对于随机存取,因为ArrayList是基于数组实现的,所以随机存取的时间复杂度为O(1),直接根据数据下标即可get或set,而LinkedList由于是使用双向链表实现,随机存取需要移动指针,时间复杂度为O(n);
  • 但是对于元素的删除和增加,如果不是在List尾部操作,ArrayList中元素的删除会涉及数组元素的移动,所以复杂度O(n)会比只单纯操作几个指针的复杂度O(1)要高。

所以在日常使用中,需要根据应用场景灵活选择,对于不需要随机存取而是只进行平凡的增加和删除的场景,使用LinkedList是较好的选择。

本文来自我的个人博客:http://blog.duchangchun.com/2018/12/29/jdk_linkedlist/

JDK源码阅读——LinkedList实现的更多相关文章

  1. JDK源码阅读--LinkedList

    public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, D ...

  2. JDK源码阅读(三):ArraryList源码解析

    今天来看一下ArrayList的源码 目录 介绍 继承结构 属性 构造方法 add方法 remove方法 修改方法 获取元素 size()方法 isEmpty方法 clear方法 循环数组 1.介绍 ...

  3. JDK源码阅读(一):Object源码分析

    最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...

  4. 利用IDEA搭建JDK源码阅读环境

    利用IDEA搭建JDK源码阅读环境 首先新建一个java基础项目 基础目录 source 源码 test 测试源码和入口 准备JDK源码 下图框起来的路径就是jdk的储存位置 打开jdk目录,找到sr ...

  5. JDK源码阅读-FileOutputStream

    本文转载自JDK源码阅读-FileOutputStream 导语 FileOutputStream用户打开文件并获取输出流. 打开文件 public FileOutputStream(File fil ...

  6. JDK源码阅读-FileInputStream

    本文转载自JDK源码阅读-FileInputStream 导语 FileIntputStream用于打开一个文件并获取输入流. 打开文件 我们来看看FileIntputStream打开文件时,做了什么 ...

  7. JDK源码阅读-ByteBuffer

    本文转载自JDK源码阅读-ByteBuffer 导语 Buffer是Java NIO中对于缓冲区的封装.在Java BIO中,所有的读写API,都是直接使用byte数组作为缓冲区的,简单直接.但是在J ...

  8. JDK源码阅读-RandomAccessFile

    本文转载自JDK源码阅读-RandomAccessFile 导语 FileInputStream只能用于读取文件,FileOutputStream只能用于写入文件,而对于同时读取文件,并且需要随意移动 ...

  9. JDK源码阅读-FileDescriptor

    本文转载自JDK源码阅读-FileDescriptor 导语 操作系统使用文件描述符来指代一个打开的文件,对文件的读写操作,都需要文件描述符作为参数.Java虽然在设计上使用了抽象程度更高的流来作为文 ...

随机推荐

  1. [Compose] 11. Use Task for Asynchronous Actions

    We refactor a standard node callback style workflow into a composed task-based workflow. For example ...

  2. Thinkphp5 Auth权限认证

    Thinkphp5 Auth权限认证 一.总结 一句话总结:四表两组关系,一个多对多(权限和用户组之间),一个一对多(用户和用户组之间) 二.Thinkphp5 Auth权限认证 auth类在thin ...

  3. 我的IT成长路——为梦想扬帆起航

    在持续了一个多月的雾霾之后,西安这座城市又看到了久违的阳光,好的天气预兆新梦想的开始.我的IT路从开始接触编程开始已经有5个年头了,从一个没有摸过计算机的农村男孩到现在学会几门编程语言的IT人,这段路 ...

  4. oracle中imp导入数据中文乱码问题(转)

    (转自  http://blog.chinaunix.net/uid-186064-id-2823338.html) oracle中imp导入数据中文乱码问题 用imp命令向oracle中导入数据后, ...

  5. 【序列操作IV】树状数组套线段树/树套树

    题目描述 给出序列 a1,a2,…,an(0≤ai≤109),有关序列的两种操作. 1. ai(1≤i≤n)变成 x(0≤x≤109). 2. 求 al,al+1,…,ar(1≤l≤r≤n)第 k(1 ...

  6. ServletContextListener和ContextLoaderListener的区别

    ServletContext 被 Servlet 程序用来与 Web 容器通信.例如写日志,转发请求.每一个 Web 应用程序含有一个Context,被Web应用内的各个程序共享.因为Context可 ...

  7. Dictionary实现(收藏的)

    源文献:https://www.cnblogs.com/InCerry/p/10325290.html 对于C#中的Dictionary类相信大家都不陌生,这是一个Collection(集合)类型,可 ...

  8. 聊聊QPS/TPS/并发量/系统吞吐量的概念

    原文:聊聊QPS/TPS/并发量/系统吞吐量的概念 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/cainiao_user/article/deta ...

  9. asp.net中C#调用存储过程

    创建存储过程: create procedure houseCount ( ), @house_count int output ) as select @house_count=COUNT(*) f ...

  10. RabbitMQ及其.NET客户端——几个小例子

    一.简单生产者-消费者(使用direct交换器) 1.生产者 var factory = new ConnectionFactory();//实例化一个工厂 factory.HostName = &q ...