java集合类源码详解-LinkedList(2)-基于JDK8

现在正式开始调试追踪源码 我们先从增加开始,首先从单个节点增加,然后是批量增加。下面是LinkedList里面的代表增加功能的函数。这里补充一下,之前忘了写,在ArrayList和LinkedList里面迭代器遍历是涉及一个设计模式的------也就是迭代器设计模式。

准备测试代码,开始测试,点击dbug

点击下一步,可以看到这里进入了个无参构造器,而且是空构造器,在LinkedList里面只有两个构造函数,ArrayList里面有三个

 

再次点击下一步,这里肯定都可以猜到,肯定会调用父类的无参构造器。

再次点击下一步,开始初始化LinkedList的类成员变量

再点击下一步,LinkerList的无参构造执行结束。

这里可以看到点东西------java里面,在进入无参构造器时,虽然这是个空构造,但是还是会去初始化成员变量,初始化后,才结束无参空构造函数的执行。

再次点击下一步。开始执行add()函数

点击下一步。这里可以看到虽然是add()方法,但是执行添加这个功能的不是add()方法,而是linkLast()方法,在ArrayList和LinkedList 有很多这样的情况。

 再次点击下一步,进入linkLast(E e)方法。这个方法是将元素e添加到链表末尾。

再次点击下一步,进入第一行代码,这行代码是将最后一个节点的引用交给变量  l 。为什么要保存最后一个节点的引用呢?、

因为 这是双向链表,待会新节点添加到链表末尾是要指向前面的节点的,而前面的节点就是旧的最后一个节点。

所以我们这里必须先保存最后一个节点的引用,即地址。

如果学过C/C++ ,这里也可以理解成把尾节点引用的那个节点的地址,交给变量  l 保存,那么 变量 l 就引用了尾节点,或者说 l 指向了尾节点(最好不这么理解)。

再次点击下一步,这里会创建一个新的节点 ,然后把这个新的节点的引用赋给newNode。

再次点击下一步,由于之前new Node(),所以这里会跳转到这个内部类的构造函数,对这个类内部成员变量进行初始化,

这里有三个参数,分别是前一个节点的引用,要添加到这个节点的值,下一个节点的引用。由于我们这里是第一个添加的节点

所以,这里的 l 是null,而添加一个节点到链表到末尾,所以这个节点的 next 不引用任何节点也为null,所以,我们这里只是把元素存到这个节点。

再次点击下一步,这里会将last 这个变量引用newNode,(在C/C++ 里面就好像尾指针指向最后一个元素),

这里可以看到,添加单个元素是在链表的尾部添加的,所以创建一个节点后,就得把 last引用 最后一个节点。

 再次点击下一步

再点击下一步,这里会根据 l (也就是last)是否为null,来判断这个链表是否有节点,如果为null,就说明没有节点,那么我们就需要把first 引用 这个新节点 newNode;

这里要注意:我不知道我前面有没有笔误写错, 我翻看了很多篇博客,有的说LinkedList有头节点,有的说没有

而老版本的jdk 是有的 ,下面是老版本

然后我们如果回到jdk8 会发现,根本就没有保存表头的变量,也就是源码里面根本就没有header变量,于是我又翻了官方的英文注释,官方英文注释从来没有说jdk8 里面LinkedList 有头节点。

看下面 j’dk8 里面 的定义

关于first 和last  官方英文注释是 Pointer to first node ,Pointer to last node

翻译成 中文是  指向第一个节点的指针,注意 第一个节点不是头节点 ,很多人认为第一个节点就是头节点,大家可以看看旧版的jdk 带头节点的情况,它专门有个header变量 引用一个头节点,这个节点 没有数据 只引用后一个节点。而 jdk8 是不存在这种情况的。   

还有很多地方证明jdk8 没有头节点。 下面是 带头节点的 链表 判空

下面是jdk8 中 LinkedList 中的判空,它这里 竟然出现了 判断头指针是否为空,如果有头节点,头节点就是一直存在的,而头指针是指向头节点的,除非没有头节点,头指针才指向第一个节点。 当我们往链表插入元素时,需要判断是否是插入的是第一个元素,也就是需要判断 链表是否为空, 而头节点的出现 ,就是避免了 在链表中 ,删除和插入 还需要去判断是否是第一个节点这种情况。 

而我们看下面的代码,居然去判断first 是否为null,这就说明是没有头节点的。 

我们即使从引用的角度来看 还是一样的。 first 引用了 第一个节点,那么first就是第一个节点,第一个节点就是first(引用其实就是取别名)。

从引用的角度来说,引用就是取别名。所以 我们添加第一个节点的时候,他就是这个链表的第一个节点。那么为什么这个第一个节点不是头节点呢,看源码里面我们发现 new Node 的时候传了值e ,而头节点是不保存值,即使保存值,也是有标志作用的值,而不是我们要存的值。所以first指向的第一个节点!再而且,如果first引用的是头节点,那么在往链表头插入数据也应该在头节点后面,而不是头节点前面,如果是在前面,这跟代码不符,而且不符合,头节点的作用(保证插入,删除的一致性)。

这里我们可以想到 写jdk8 源码的人 为什么 取名为first 了吧 ,first就是第一的意思。

而jdk 老版本有头节点, 所以jdk 源码的作者 专门定义了一个变量 header  ,见名知意 ,是不是啊,header 是不是就是头的意思啊,

所以 它自然表示的是头节点。

而我们的jdk8 LinkedList其实就是这种数据结构

其实就是这种结构

好了,我们继续调试

再次点击下一步,此时判断是否没有节点,如果没有节点,就把头指针指向第一个节点,这里肯定是true

再次点击下一步

再次点击下一步,最后这个LinkedList对象的size+1,modcount++

再次点击下一步

执行结束

总结:链表这种数据结构,最开始是出现在C/C++里面的,java里面没有指针,只有引用,但是说白了,引用就是指针的再次封装。

今天的LinkedList的源码学习就到此为止了。如有不对请指出,大家一起学习进步

猜你喜欢

转载自blog.csdn.net/qq_37889257/article/details/84839619