参考链接
根据参考链接的思路,分析源码可以以下几个方面进行:
- 查看类图
- 成员变量
- 构造方法
- 常用方法(增删改查)
- 实现Deque接口部分
- 遍历
1. 查看类图
Collection总的类图参考:链接
LinkedList的类图如下,其中实线为继承关系,虚线为接口实现关系。
LinkedList继承了AbstrackSequentialList- 实现了
List接口以及Deque双向队列接口 LinkedList和ArrayList一样实现了序列化接口Serializable和Cloneable接口
2. 成员变量
// 节点个数
transient int size = 0;
// 链表的头节点
transient Node<E> first;
// 链表的尾节点
transient Node<E> last;
//
private static final long serialVersionUID = 876323262645176354L;
3. 构造方法
// 空参构造
public LinkedList() {
}
// 使用一个集合来构造另一个集合,将原始集合的元素依次添加给新构造的集合
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
其中addAll方法为:
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
进一步调用下面的addAll方法:
/**
* 在 index 节点前插入包含所有 c 集合元素的节点。
* 返回值表示是否成功添加了对应的元素.
*/
public boolean addAll(int index, Collection<? extends E> c) {
// 查看索引是否满足 0 =< index =< size 的要求
checkPositionIndex(index);
// 调用对应 Collection 实现类的 toArray 方法将集合转为数组
Object[] a = c.toArray();
//检查数组长度,如果为 0 则直接返回 false 表示没有添加任何元素
int numNew = a.length;
if (numNew == 0)
return false;
// 保存 index 当前的节点为 succ,当前节点的上一个节点为 pred
Node<E> pred, succ;
// 如果 index = size 表示在链表尾部插入
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
// 遍历数组将对应的元素包装成节点添加到链表中
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
//如果 pred 为空表示 LinkedList 集合中还没有元素
//生成的第一个节点将作为头节点 赋值给 first 成员变量
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
// 如果 index 位置的元素为 null 则遍历数组后 pred 所指向的节点即为新链表的末节点,赋值给 last 成员变量
if (succ == null) {
last = pred;
} else {
// 否则将 pred 的 next 索引指向 succ ,succ 的 prev 索引指向 pred
pred.next = succ;
succ.prev = pred;
}
// 更新当前链表的长度 size 并返回 true 表示添加成功
size += numNew;
modCount++;
return true;
}