
与 ArrayList 一样实现了 List 接口,只是 LinkedList 底层结构为链表.在插入和删除时更优于 ArrayList,而随机访问则比 ArrayList 稍逊.
其允许元素包括 null.除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
该类还实现了 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。 所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端).


LinkedList 继承自 AbstractSequentialList,又实现了 List、Deque、Cloneable、Serializable等接口. AbstractSequentialList相较于AbstractList(ArrayList的父类),只支持次序访问,而不支持随机访问,因为它的get(int index) ,set(int index, E element), add(int index, E element), remove(int index) 都是基于迭代器实现的。
Deque - 线性 collection,支持在两端插入和移除元素,定义了双端队列的操作.
双向链表定义方式.




可以看出,这是一个典型的双向链表的结构



下面开始看各大核心 API 细节.

linkLast(E e)

add(E e)等价于addLast(E e),因为 LinkedList 实现了 Deque 接口.


核心都是linkLast方法.


linkFirst(E e)



首先调用checkPositionIndex检查index值是否在范围内
checkPositionIndex

isPositionIndex

如果index在最后的话,就调用在尾部插入的函数,否则调用LinkBefore
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void linkBefore(E e, Node<E> succ) { //在succ节点前插入newNode // assert succ != null; // 将 succ 的前驱结点记为 pred final Node<E> pred = succ.prev; // 以 pred 为前驱结点,以 succ 为后继节点新建 newNode final Node<E> newNode = new Node<>(pred, e, succ); // 将 newNode 设为 succ 的前驱节点 succ.prev = newNode; if (pred == null) // 若原 succ 的前驱节点为null,则新插入的就是 first 头节点 first = newNode; else // 否则,要把newNode设为原来pred节点的后继节点 pred.next = newNode; size++; modCount++; } |
|---|



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private E unlinkFirst(Node<E> f) { // assert f == first && f != null; // 将 f.item 暂存 element final E element = f.item; final Node<E> next = f.next; f.item = null; f.next = null; // 辅助 GC // next成为实际的first节点 first = next; if (next == null) // next为空的话,因为next是第一个节点,所以链表都是空的,last也为空 last = null; else next.prev = null; // next不为空,也要将它的前驱节点记为null,因为next是第一个节点 size--; // 节点数减一 modCount++; // 修改计数器加1 return element; } |
|---|

删除非空的尾节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private E unlinkLast(Node<E> l) { // assert l == last && l != null; final E element = l.item; // 将尾节点的前驱节点记为 prev,它将成为last节点 final Node<E> prev = l.prev; l.item = null; l.prev = null; // 辅助 GC // 设置刚才记录的前驱节点为last last = prev; if (prev == null) // prev 为 null,说明要删除的l前面原来没前驱节点,那么删了l,整个链表为空 first = null; else // prev成为最后一个节点,没有后继节点 prev.next = null; size--; modCount++; return element; } |
|---|
在指定index删除

检验index是否合法.如果删除成功,返回删除的节点。 具体实现在unlink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; } |
|---|

删除首次出现的指定元素(如果存在)


转存失败重新上传取消

迭代,比对,然后返回值而已.

node(int index)

返回此列表的第一个元素

返回此列表的最后一个元素。

返回此列表中首次出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1。

返回此列表中最后出现的指定元素的索引,如果此列表中不包含该元素,则返回 -1

面试中,经常把LinkedList 和 ArrayList 对比质问,注意对比式学习.