注:本文解析的 LinkedList 源代码基于 Java 1.8 。
Header
List 集合中,之前分析了 ArrayList ,还剩下了 LinkedList 没有分析过。那么趁着今天有空,就把 LinkedList 的内部原理来讲讲吧。
LinkedList 是有序并且可以元素重复的集合,底层是基于双向链表的。也正因为是链表,所以也就没有动态扩容的步骤了。
源码分析
构造方法
1 | public LinkedList() { |
构造方法一个是默认的,另外一个是传入一个集合,然后调用 addAll 方法添加集合所有的元素。
Node
LinkedList 既然作为链表,那么肯定会有节点了,我们看下节点的定义:
1 | private static class Node<E> { |
每个节点都包含了前一个节点 prev 以及后一个节点 next ,item 就是要当前节点要存储的元素。
add(E e)
1 | public boolean add(E e) { |
在 linkLast(E e)
中,先去判断了原来的尾节点是否为空。如果尾节点是空的,那么就说明原来的列表是空的。会将头节点也指向该元素;如果不为空,直接在后面追加即可。
其实在 first 之前,还有一个为 null 的 head 节点。head 节点的 next 才是 first 节点。
add(int index, E element)
1 | public void add(int index, E element) { |
在 add(int index, E element)
中主要就看 linkBefore(element, node(index))
方法了。注意到有一个 node(index)
,好奇究竟做了什么操作?
1 | Node<E> node(int index) { |
原来是为了索引得到 index 对应的节点,在速度上做了算法优化。
得到 Node 后,就会去调用 linkBefore(element, node)
。
1 | void linkBefore(E e, Node<E> succ) { |
这段代码和之前的很类似,了解链表节点插入的同学对这段代码应该很 easy 了。
addAll(Collection<? extends E> c)
1 | public boolean addAll(Collection<? extends E> c) { |
在 addAll(Collection<? extends E> c)
内部直接调用的是 addAll(int index, Collection<? extends E> c)
。
1 | public boolean addAll(int index, Collection<? extends E> c) { |
addAll(int index, Collection<? extends E> c)
其实就是相当于多次进行 add(int index, E element)
操作,在内部循环添加到链表上。
get(int index)
1 | public E get(int index) { |
在内部调用了 node(index)
方法,而 node(index)
方法在上面已经分析过了。就是判断在前半段还是在后半段,然后遍历得到即可。
remove(int index)
1 | public E remove(int index) { |
remove(int index)
中调用了 unlink(Node<E> x)
方法来移除该节点。
1 | E unlink(Node<E> x) { |
remove(Object o)
1 | public boolean remove(Object o) { |
remove(Object o)
的代码就是遍历链表,然后得到相等的值就把它 unlink(x)
了。至于 unlink(Node<E> x)
的代码,上面已经分析过啦。
set(int index, E element)
1 | public E set(int index, E element) { |
clear()
1 | public void clear() { |
Footer
LinkedList 相对于 ArrayList 来说,源码会复杂一点。因为涉及到了链表,所以会有 prev 和 next 之分。但是静下心来阅读,还是可以看懂的。
基础集合类的源码都看得差不多了,目前为止一共分析了 ArrayList、LinkedList、HashMap 和 HashSet 四个类。
之后有空的话还有更多的集合类会进行源码解析,那么好好努力吧。
v1.5.2