当前位置: 首页 > news >正文

java linkedlist源码_深入分析java集合类LinkedList(源码分析)

这篇文章开始介绍LinkList。他和ArrayList有一些相似,在上一篇文章讲解 ArrayList时,我们知道ArrayList是以数组实现,它的优势是查询性能高,劣势是按顺序增删性能差。如果在不确定元素数量的情况时,不建议使用ArrayList。这种情况下,我们就可以使用LinkedList了。所以这篇文章,旨在从源码的角度进行分析和理解LinkedList。

OK,开始今天的文章。

一、LinkedList认识

1、由链表认识LinkedList

我们应该都学过数据结构与算法,如果你知道链表的实现原理,那么你就可以直接看LinkedList的基本认识了,可以跳过本小节,如果你没学过,或者是不牢固,那么就先看看本小节再往下面学习吧。

我们想要认识链表有一个例子可以形象的去表示,我们都看过警察捉贼的故事,比如说警察现在要抓一个小偷,得知小偷在A处,结果警察一去发现没有,但是A处的相关人员说小偷可能在B处,结果警察又去了B处,发现又没有,被告知可能在C处,警察又去了C处,没有之后得到情报又去了D、E、F等等。最终抓获了小偷,我们把整个抓捕过程其实就可以看成一条线索链,或者说叫做链表。我们可以看到每一处地点,我们就可以看作链表的一个节点,每一个节点要包含两个信息:一个是本地的信息,一个是下一个地点的信息。

下面使用一张图来直观的表示一下:

5bff820a280efdb48e4603ad21448257.png

下面我们就可以对上面的这个链表进行一个分类:

单链表:就是上面我们提到的,只有下一处的地址。双链表:表示不仅存储下一处的地址,还存储上一处的。

d3d79309aabb1a6167b1c26ad2b2be2a.png

循环链表:就是说整个地址构成一个循环链。有序链表:以某个标准,给链表的元素排序,比如比较内容大小、比较哈希值等在上面我们已经看到了链表的实现方式还有分类,当然链表还有一些基本的特性,需要我们去了解:

在数组中,是通过索引访问元素的。但是链表不能,只能通过链一个一个的找。这个说明了链表的优势不在快速找到元素。链表的优势在于定点删除/插入元素,因为链表影响的最多就是给定元素的左右的两个链这里就有个trick, 由于改变右边链的时候,如果不先存储右边的结点,那么右边的结点的元素就找不到了,所以改变结点的指针的时候,会先暂存下一个结点。另外单链表找不到它的父亲结点(上一个结点),所以会经常用prev来暂存上一个结点。2、认识LinkedList

我们的LinkedList就是以双向链表实现的。既然它是以链表来实现的,所以也会有链表的基本特性。又因为其是使用双向链表来实现的,所以重点还是在于双向链表的特性

链表无容量限制,但双向链表本身使用了更多空间,也需要额外的链表指针操作。除了实现List接口外,LinkedList还为在列表的开头及结尾get、remove和insert元素提供了统一的命名方法。这些操作可以将链接列表当作栈,队列和双端队列来使用。3、从继承关系看LinkedList

为此我们需要先知道LinkedList在整个java集合框架体系里面处于一个什么样的位置。一张图来说明:

6fa7365c5fd77389ec66b947f7b080fb.png

从上面我们发现LinkedList的最根部就是实现了Collection接口。下面我们去掉其他影响集合,从LinkedList为出发点来看继承关系:

8bf14d92b6a8b0295decb54d2ea6343f.png

从上面我们可以看到,LinkedList继承的类与实现的接口如下:

Collection 接口、List 接口、Cloneable 接口、Serializable 接口、Deque 接口(5个接口)

AbstractCollection 类、AbstractList 类、AbstractSequentialList 类(3个类) 。

其中Deque定义了一个线性Collection,支持在两端插入和删除元素。

二、分析LinkedList

在上面从链表到继承关系,我相信你应该对LinkedList有一个基本的了解了。但是下面的分析才是最重要的一环。其实LinkedList中的增删改查操作底层就是基于链表的增删改查的操作,我们可以类比去记忆,然后自己动手去写一个LinkedList

1、Api操作分析

(1)节点Node结构

c997aae773ff023f666302b3731bc2d7.png

从上面的node定义,我们就可以看到这是一个双向的链表。

(2)构造方法

aa33fe00d3f39335c8fdc31ae2a26772.png

(3)增加操作

首先是插入单个节点:

e1b98f473884c575c2fbdb22ac7ca0c0.png

增加操作一定会更改modCount,这里面涉及到了fail-fast机制。可以翻看我之前的文章。

(4)删除操作

ca625a804003e14a8df6febfd584403f.png

(5)更改操作

361762423b4115a8973bb5a45bc76641.png

(6)查操作

a12b954f538a95ab3e5b632ccd9170c0.png

(7)其他操作

766ecbf265be6f29a62c6065abbf66a3.png

2、遍历LinkedList

(1)一般的for循环(随机访问)

904cb37449037a35bcdc7b8ba5e19c2f.png

(2)for--each循环

bca2ebf2b97a9f5d12db4df535d46a65.png

(3)迭代器iterator

963f558a75da8ac5c7b83de17fa70ec2.png

(4)用pollFirst()来遍历LinkedList

fe13ac52b82552042e2c1c057c0aecee.png

(5)用pollLast()来遍历LinkedList

319867ee2111de787f319e5cfd5b863b.png

(6)用removeFirst()来遍历LinkedList

d75459f76ead9e5fffeef49e7ba94ec8.png

(7)用removeLast()来遍历LinkedList

74f86d2c38692fd2a19171b868b45770.png

注意:在链表结构实现的数据集合中,最好采用Iterator或者foreach的方式遍历,效率最高。

小结:

(1)底层实现:LinkedList的实现是基于双向链表的,且头结点中不存放数据。

(2)构造方法:无参构造方法直接建立一个仅包含head节点的空链表;包含Collection的构造方法,先调用无参构造方法建立一个空链表,而后将Collection中的数据加入到链表的尾部后面。

(3)查找删除:源码中都划分为该元素为null和不为null两种情况来处理,LinkedList中允许元素为null。

(4)LinkedList是基于链表实现的,因此不存在容量不足的问题,所以这里没有扩容的方法。

(5)LinkedList是基于链表实现的,因此插入删除效率高,查找效率低(虽然有一个加速动作)。 (6)注意源码中还实现了栈和队列的操作方法,因此也可以作为栈、队列和双端队列来使用。

2eb2987126d2ab9f5e16985d2d8b2868.png

三、linkedList与ArrayList对比分析

下面将对ArrayList与LinkedList进行对比,主要从以下方面进行

相同点

1.接口实现:都实现了List接口,都是线性列表的实现

2.线程安全:都是线程不安全的,都是基于fail-fast机制

不同点

1.底层:ArrayList内部是数组实现,而LinkedList内部实现是双向链表结构

2.接口:ArrayList实现了RandomAccess可以支持随机元素访问,而LinkedList实现了Deque可以当做队列使用

3.性能:新增、删除元素时ArrayList需要使用到拷贝原数组,而LinkedList只需移动指针,查找元素 ArrayList支持随机元素访问,而LinkedList只能一个节点的去遍历

OK,今天的文章就到这,如有问题还请批评指正

相关文章:

  • 从诚恳出发,迈向自我实现
  • java 中的map_浅谈java中Map的用法
  • 学习SWT的一些资源
  • java http同步请求_java websocket 如何实现消息同步返回,类似 http 请求数据返回结果...
  • 一条路给出了道题:“还有一元钱去了哪里???”
  • java atm项目_java实现ATM取款项目
  • pyhon使用http代理服务器和POP3、SMTP邮件服务器
  • ubuntu server安装php mysql_Ubuntu杂记——Apache+PHP+MySQL的安装
  • 基于TCP/IP的手机聊天游戏(附带源码和解释)之共享类
  • java杰森_杰森 - BlogJava
  • 基于TCP/IP的手机聊天游戏(附带源码和解释)之服务器端类
  • java显示图片缩略图_java中生成图片的缩略图
  • 基于TCP/IP的手机聊天游戏(附带源码和解释)之客户端类
  • 在DataGrid等控件中添加自动编号的列
  • java 循环队列实现_Java实现循环队列
  • JavaScript-如何实现克隆(clone)函数
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • Babel配置的不完全指南
  • eclipse(luna)创建web工程
  • HTTP--网络协议分层,http历史(二)
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • mysql常用命令汇总
  • React Transition Group -- Transition 组件
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • text-decoration与color属性
  • Vim Clutch | 面向脚踏板编程……
  • Vue 2.3、2.4 知识点小结
  • 从重复到重用
  • 反思总结然后整装待发
  • 高度不固定时垂直居中
  • 基于组件的设计工作流与界面抽象
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 微信小程序--------语音识别(前端自己也能玩)
  • 以太坊客户端Geth命令参数详解
  • 运行时添加log4j2的appender
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 正则表达式-基础知识Review
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​虚拟化系列介绍(十)
  • ​用户画像从0到100的构建思路
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #include到底该写在哪
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #每日一题合集#牛客JZ23-JZ33
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (七)c52学习之旅-中断
  • (原)本想说脏话,奈何已放下
  • (转)拼包函数及网络封包的异常处理(含代码)
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程