LinkedList源码简单分析
一. 简介
LinkedList是实现了List和Deque接口的双链表,它实现了List接口的所有可选的方法,允许添加所有的元素,包括null。LinkedList还实现了Cloneable和Serializable接口,所以它还具有可复制和序列化的能力。与ArrayList相比,LinkedList的底层是基于链表,所以在数据的插入和删除方面性能要优于ArrayList,但在随机访问方面ArrayList的性能更好。
二. 属性
2.1 LinkedList基本属性
2.1.1 first
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
- first链表的头指针,指向第一个结点
2.1.2 last
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
- last链表的尾指针,指向最后一个结点
2.1.3 size
transient int size = 0;
- 链表的长度
2.2 LinkedLink内部类Node属性
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
2.2.1 item
- LinkedList中的数据是存储在节点上的,item就是存储数据的地方。(LinkedList本质跟链表一样)
2.2.2 next
- next,储存下一个节点的指针(地址),如果是最后一个就设置为null。
2.2.3 prev
- prev,存储上一个结点的指针,如果是头结点就置为null
三. 构造方法
3.1 无参构造
/**
* Constructs an empty list.
*/
public LinkedList() {}
- 构建一个空列表
- first和last都为null,size长度等于0
3.2 有参构造
- 构建一个包含指定集合元素的链表,通过集合的迭代器将元素返回
- 首先调用无参构造this()
- 然后调用addAll©方法
四. 主要的操作方法
4.1 addAll©
- 该方法默认将集合c中的元素追加到LinkedList链表的最后面
4.2 node(index)
- 通过指定的元素下标,返回结点
- index < (size >> 1),使用折半查找的算法查询结点,快速检索,提高性能。
addAll(index, c)
-
调用checkPositionIndex方法,检查下标是否越界。
-
toArray,将集合转化为数组a。
-
numNew,数组a的长度,如果长度等于零,下面操作没有意义,直接返回false。
-
接下来的if/else包含的代码块,主要作用就是判断数组a中的所有元素添加的位置。
-
index==size,数组中的元素追加到链表(LinkedList)的末端。
- 尾指针赋值给pred,succ=null。
-
0<=index<size,数组中的元素插入到链表的任意位置(除了末端)。
-
通过node方法找到该索引所在的结点,返回值赋值给succ。
-
将succ结点的prev指针域的值赋值给pred。
- 集合c中的所有元素将会在pred和succ中间插入
- 集合c中的所有元素将会在pred和succ中间插入
-
-
-
for循环就是将数组a中的所有元素封装成Node结点,根据不同的情况,依次链接到链表上(linkedList)
-
最后链表的长度加上数组a的大小numNew,操作数modCount加一
4.4 add(E e)
- 调用add(E e)实际上是在调用linkLast(E e)
- linkLast方法,默认将新添加的元素,放在最后面末端
- l==null,意味着当前链表是空链表,新添加的结点是头结点,相反,将新结点指针连接到尾结点的next指针域。
- 最后链表长度加一,操作数加一
4.5 add(index, element)
- 调用add(index, element)方法,首先需要检查索引是否越界。
- 如果index==size,元素添加到末端,直接调用linkLast方法。
- 元素添加到其他地方,直接调用linkBefore方法
- 首先通过Node方法,找到要被替换位置的结点。
- 根据插入的位置(头部或中间部分)不同,插入结点的方式也不同。
4.6 remove(Object o
- remove(Object o)删除节点的大致过程是:
- 先遍历整个链表,根据条件找到要被删除的结点
- 调用unlink方法
- 该方法根据被删除结点所处的位置(头结点,尾结点)不同,操作也不同
- 处在头结点:先将头指针指向被删除结点的下一个结点,然后将该节点的prev指针域置为null
- 处在尾结点:先将被删除结点的上一个结点的next的指针域置为null,被删除结点的prev指针域也置为null,最后让链表的尾指针指向被删除结点的前一个结点。
- 将被删除结点的数据域item置为null
- 链表大小减一,操作数加一
- 该方法根据被删除结点所处的位置(头结点,尾结点)不同,操作也不同
- 因为LinkedList链表可以添加null,所以remove方法中有两种情况(o==null || o!=null)。
4.7 remove(index)
- 根据下标删除结点很简单,直接调用unlink方法将结点移除,当然首先还是要检查下标是否越界
4.8 get(index)
- get方法也很简单,直接调用node()方法通过下标找到结点,然后返回结点数据域的值。
五. 感谢
- 本篇笔记是我看了微信公众号好好学java中的文章写出来的,内容的当然没有大佬写的那么详细和有条理,所以大家如果有兴趣可以去订阅一下。