前几篇文章分析过 List 接口的一个重要实现 ArrayList,本篇博客开始介绍另一个重要实现 LinkedList。
一、与 ArrayList 的区别
ArrayList 使用数组存储数据,且数组的长度大于实际存储的数据以便增加和插入元素,允许直接按序号查找元素,但是插入元素要涉及数组元素移动等内存操作,所以查询快,插入慢。而LinkedList使用双向链表实现存储,按序号查找数据需要进行前向或后向遍历,查找就变慢了,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
二、LinkedList 继承关系
不同于 ArrayList ,LinkedList 实现了 Deque 接口,使得 LinkedList 可以被当作堆栈和队列来使用。
三、源码解析
1、内部类Node
LinkedList 中的每一个元素就相当于一个 Node 类,LinkedList 集合就是由多个 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;
}
}
此时,集合中有三个元素,为三个 Node 对象
2、add(E e)
// 将指定的元素添加到末位
public boolean add(E e) {
linkLast(e);
return true;
}
linkLast(e) 方法:
/**
* Links e as last element.
*/
void linkLast(E e) {
// 先保存最后一个节点
final Node<E> l = last;
// 实例化新的Node对象,prev 指向当前最后节点,item 值为添加的元素, next 为 null
final Node<E> newNode = new Node<>(l, e, null);
// 新的节点即为最后的节点
last = newNode;
/*
* 如果最后一个节点为null,则集合为空,newNode 节点即为 first 节点
* 不为null,将 newNode 节点链接到尾部
*/
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
LinkedList 没有扩容机制,所以 add() 方法较之 ArrayList 的 add() 方法,速度较快。
3、add(int index, E element)
// 将元素插入集合中的指定位置
public void add(int index, E element) {
// 检查下标是否越界,index值在 [ 0, size]之间