侧边栏壁纸
  • 累计撰写 7 篇文章
  • 累计创建 7 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

JDK源码学习-LinkedList

小白
2022-08-03 / 0 评论 / 0 点赞 / 104 阅读 / 14125 字

面试的时候经常问到ArrayListLinkedList的区别当然我们知道一个是用数组,来存储一个是用链表来存储,然后根据数组和链表的特性增删查改的速度各有不同,这里就不在赘述了,(因为那个我已经记住了应该不会忘记了就用不着记了嘿嘿~)现在只想记录JDK的源码实现,当然其实记录也是表面上的记录,就像读书百遍里面的第一遍那样。

这次我们一样从构造函数,添加元素获取元素这些方面来卡看它的实现。

属性

先看看它有那些属性,看看注释上面怎么说

image-1659541743612

看起来它好像主要只有三个属性firstlastsize

image-1659541758200

不管是根据名字还是注释可以看到分别是表示存储的元素的第一个和最后一个和存储了多少个元素了,乍一看是不是没有存储数据的地方啊,哈哈哈其实不是的,这里先猜测一下,因为它是链表结构,通过first找到第一个元素,然后Node里面有指向下一个元素的指针,这样一个一个连起来就是链表,然后来实现数据存储的.

这里值得注意的是firstlast是一个Node的类型

image-1659541766223

看起来Node是他的一个静态类部类用来实现链表结构的,不出意外的里面有三个属性表示当前节点、前驱节点和后一个节点,果然这样就能实现链表的遍历了,最后它是怎么做的我们还是来看看具体操作。

构造方法

image-1659541774317 看起来它就两个构造方法一个无参的什么都没有做,看注释说是构造一个空的List,一个带集合参数的方法是将集合里面的元素作为初始值添加到List

image-1659541784925

添加元素

image-1659541792316 没想到add方法还挺多的

add(E e)

先看添加指定元素的方法

image-1659541801435

看起来是调用了一个链接到最后一个元素的方法

image-1659541809488

看起来他是直接通过last属性找到最后一个元素,然后将新添加的元素作为其next节点这不就在最后一个的后面,不就是最后一个了,在将last指向新创建的这个节点,完美啊,怪不得要存储last节点 找起来太方便了,不然你想想,不存储last节点是不是要从first一个一个循环往下找直到next指向了null,这不就很完美的解决了一个遍历问题,心中竖起了大拇指,太牛逼了我什么时候能这么厉害。

最后在给size加个1记录下来增加了一个元素了,以后要获取存储了多少个元素岂不是也可以直接使用这个size了,哇太牛逼了我们看看是不是这么写的

image-1659541826217

哇~还真是这么写的太牛逼了,我什么时候能这么厉害,想想要是没有size的话岂不是还要遍历了链表一个一个数,太可怕了。

add(int index, E element)

我们继续看看这个在指定位置添加一个元素

image-1659541833525

显示判断了一下是否越界,要在0到size之间不然还会抛出一个异常

image-1659541850305 image-1659541856426 然后有判断如果要插入的位置就是等于size的化表明是插入到最后一个直接就使用我们前面看的方法链接到最后一个了

不然的话就要去找到传入的位置的Node

image-1659541870173

查找的时候有点意思,没有直接从first开始数而是计算了一下size >> 1相当于就是取一半的意思,但是这位移计算可比用除法快多了,果然优秀的代码都有使用位移计算,太厉害了,不知道我上面时候能有这么厉害,如果要取的元素位置小于size的一半也就是链表的前半段直接从last往后一个一个数然后找到它返回出去

如果要找的位置大于size的一半那就是在后半段咯,这个时候就是从last节点也就是最后一个节点往前面开始倒数知道数到要找的那个位置数那就返回出去咯。

image-1659541879682

然后就调用到linkBefore方法了,然后就是一顿指针指向操作,然后size加1结束~,后面的modCount修改之后看快速失败的时候再说。

addFirst(E e)&addLast(E e)&other

至于addFirst(E e)&addLast(E e)这两个方法应该就比较简单了,就是调用我们前面看到的linkLastlinkBefore来插入的.

至于addAll方法就不想看了,估计也没啥特别的就是一个一个添加到链表后面

获取元素

获取元素看起来有三个方法get(int index)getFirst()getLast()

image-1659541889698 获取方法也一样比较简单比如第一个添加到指定位置

image-1659541896011

使用之前看到的那个方法获取到指定位置的Node然后返回出去 后面两个getFirstgetLast就没有什么好说的了当然就是获取firstlast直接返回出去了

image-1659541906502

移除元素

我们继续看看移除的方法 image-1659541917841 比如移除指定位置的元素

image-1659541926106

还是找到指定位置的元素然后调用的一个unlink方法,和普通链表一样就是一些支持指向操作把要移除的指针给去掉

image-1659541933474

然后移除指定元素就是循环遍历链表找到相同的元素就调用unlink解除他的指针了,只不过对null是单独的逻辑而已(哈哈哈我猜测是null不能使用equls方法吧)

image-1659541945384

然后余下的那些移除方法应该都差不多了,最后是用unlink来取消他的指针,所以问题就是找到要移除的元素的问题了,当然你肯定也能想到移除第一个元素和最后一个元素是这么找到第一个元素和最后一个元素的了

快速失败

依然以后来说

序列化

序列化和反序列化方法他都复写了

image-1659541954840

可以看到它先写了size然后在一个一个写Node节点,读取的时候也是县读取size然后一个一个读取节点添加到链表后面

双端队列

其实在开始的时候我没有看它实现了那个接口继承了那些类,在看他的方法的时候才发现他有这么多方法很多是队列的,才发现它实现了双端队列的接口,但是队列相关的操作都是比较简单的,就不一一看了,大多数复用前面看的方法添加获取数据

image-1659541963321

对数据有操作的就是一些指针操作移除元素的指针了,基本就是这样,相同重复的代码看多了就没有激情了,先少看点哈哈哈哈哈哈~

image-1659541976490

0

评论区