1 继承结构图

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

2 数据结构

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

  // 记录List长度
  transient int size = 0;   // 指向LinkedList第一个节点
  transient Node<E> first;   // 指向LinkedList最后一个节点
  transient Node<E> last;   // Node Class如下
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;
}
}

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

3 构造方法

    public LinkedList() {}

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

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

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

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

4 一些方法介绍

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

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. 【10.58%】【codeforces 721C】Journey

    time limit per test3 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...

  2. c++ 成员函数指针

    C++中,成员指针是最为复杂的语法结构.但在事件驱动和多线程应用中被广泛用于调用回叫函数.在多线程应用中,每个线程都通过指向成员函数的指针来调用该函数.在这样的应用中,如果不用成员指针,编程是非常困难 ...

  3. ubuntu系统安装和配置

    1.分区信息 1.1 /boot分区 这个分区包括了操作系统的内核和在启动系统过程中所要用到的文件.假设有了一个单独的/boot启动分区,即使基本的根分区出现了问题,计算机依旧可以启动.这个分区的大小 ...

  4. Android下载文件提示文件不存在。。。 java.io.FileNotFoundException

    遇到这个错误java.io.FileNotFoundException,事实上文件是存在的,把地址复制到手机浏览器都能够直接下载的,但为嘛不能下载呢. Error in downloadBitmap ...

  5. Linux网络编程——原始套接字能干什么?

    通常情况下程序员接所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的 Socket,针对于面向连接的TCP 服务应用: (2)数据报式套接字(SOCK ...

  6. Ubuntu安装编译OpenCV一键脚本(带ffmpeg)

    1.切换到用户文件夹 cd ~ 2.新建一个文件.命名为opencv.sh 脚本例如以下: version="$(wget -q -O - http://sourceforge.net/pr ...

  7. 动态创建Fragment

    在android3.0之前.每创建一个界面就要新创建一个activity. 在3.0之后引入了Fragment.相当于一个轻量级的activity.不须要在清单文件配置. 先来看下怎样创建和使用Fra ...

  8. WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush)

    原文:WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush) 前面我们提到了LinearGradientBrush可以用来画渐变填充图,那么我们同时也可以使用ImageBr ...

  9. 【BZOJ 1038】[ZJOI2008]瞭望塔

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1038 [题意] [题解] 可以看到所有村子的瞭望塔所在的位置只会是在相邻两个村子所代表 ...

  10. solrj 7.x Expected mime type application/octet-stream but got text/html.

    出现这种情况是因为baseurl填写错误,最开始的时候我写的是用tomcat启动后浏览器中访问solr的地址 结果就出现了如题的异常,当然提示的是404,还有可能提示405,Method not al ...