首先认识一下LinkedList,LinkedList是list的子类,其增删快,而查找慢,其底层依赖的是双向链表。接下来,我还是会从常用的API来认识一下LinkedList
1.首先是无参构造器
其实也没有干什么,就是生成了几个成员变量(这里遗留一个问题,为什么成员变量是transient?),(1)长度(2)链头(3)链尾
上面就是节点Node,每个节点连接着前后节点,并且存储数据。(之前很好奇,为什么Node里面并没有存储小标,那么是如何保证使用到get(index)的呢)
2.看一下add(E e)方法。
其实简单的分析一下将新赋予的值放入新的Node当中,再将新的Node放入链表last.next里,最后size++,修改次数++。
3.接着是常用的get(index)方法
(1)首先判断有没有越界,或者为负数。
(2)上面提出了一个问题,为什么内部类Node没有下标,但是却可以使用get(index),以前我一直以为是Node储存了下标。接下来给出解答,我们进入node(index)方法
这里其实是一个判断,先确认index离头还是离尾近,然后再从相应位置依次查找。这样省去了一般的事件,也因此LinkedList查找较慢,其时间复杂度为O(n)。(这里就不去看getFirst()和getLast()了,因为这两个方法就是从first和last里面取值。这两个方法时间复杂度为O(1))
4.然后看一下add(index,Object)方法
(1)首先还是检查index是否越界,以及是否为负数。
(2)当index=size这种情况可以参考add(Object)方法。这里主要看linkBefore(element,node(index))
比如 Node1,Node2,Node3这三个node,在2的位置插入4,那么就是将Node1的next指向Node4,Node4的prev指向Node1,Node4的next指向Node2,Node2的prev指向Node4,size++,修改次数++。
5.讲一下remove()
进去看源码会发现,就是remove掉链头,将链头转交给下一个,并且返回remove掉的数据。
6.remove(index)
(1)首先还是判断index的问题
(2)进入unlink方法,先找到index对应的node
其实也是将前面的node和后面的node的next,prev指向改变。并且返回存储的数据
7.remove(Object)
其实也就是调用了unlink(node)方法。
8.看一下linkedList的成员变量
其头尾都是transient修饰的,那么它也一定有readOject()、writeObject()方法。
先看一下writeObject()方法。
就是将size写出去,然后从链头开始循环,然后写出node存放的数据。
接着看readObject()方法。
首先读出size,然后接着进入重要的构成Node链
大致的流程就是从链头开始,依次向后放入元素,形成链表。
9.还是和ArrayList一样,我们看一下LinkedList的iterator接口(其作用参考请参考arrayList中写到的iterator)
还是从切入点进入。
首先看一下iterator()。
调用到了父类AbstractSequentialList的iterator()方法,在调用listlistIterator()方法
然后再接着调用其父类AbstractList的listIterator()方法。
进入到
由于LinkedList重写了该方法,那么我们看一下LinkedList的该方法
大致讲一下过程(1)检查是否越界(2)返回一个ListItr对象,并且这时候将这个链条的链头first赋予next
lastReturned:返回的上一个节点
next:当前节点
nextIndex:节点下标+1
expectedModCount:修改次数,确保linkedList未被修改
接着看一下next()
大致步骤(1)先确保没有被修改过(2)判断游标位置(3)将当前的节点赋值给lastReturned(4)将当前节点往前移动。(5)下标++(6)返回数据。
LinkedList相比ArrayList独有的iterator的方法,previous()
步骤如下:(1)先确保没有被修改过(2)判断游标位置(3)将next当前节点赋予lastReturned(4)将next往前移动(5)nextIndex--(6)返回当前节点数据
最后还是看一下remove()方法。
大概步骤(1)判断是否修改过(2)判断是否遍历完毕(3)移除这个节点(4)将expectedModCount++是为了unlink()方法时modCount++保持一致。