本文由 Oo鲁毅oO 首发于 掘金,下方为原文链接
源码分析|LinkedList
1.什么是LinkedList
LinkedList是一个线性的,以双向链表形式实现的有序性的集合,因为是链表实现,所以执行添加和删除操作时效率比较高,执行查询操作时效率比较低。
2.LinkedList构造方法分析
public LinkedList() {
}
当不传入参数时,会创建一个空的LinkedList
3.add()方法
list.add("aaa");
当第一次调用add()
方法时,点击add()
显示如下内容
public boolean add(E e) {
linkLast(e);
return true;
}
在添加方法的内部会调用linkLast
方法,再点进去
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
代码首先会执行Node<E> l = last
,其中last是transient Node<E> last;
,下一个语句是包含前驱l
和元素本身e
以及后继null
的Node
类型的节点赋值给newNode
节点,再将newNode
赋给last
及first
。这就相当于
最后将size
进行维护
4.addFirst()方法
list.add("aaa");
list.addFirst("hello");
点击进入会发现
public void addFirst(E e) {
linkFirst(e);
}
再点击linkFirst
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
先是将transient Node<E> first;
赋值给f
,因为前面添加了元素aaa
,所以f
会指向aaa
节点。再将前驱为null
元素值为e
后继为f
的节点Node
赋值给newNode
,再将newNode
赋值给first
,此时first
和last
已经不指向相同的元素了,再将f
的前驱指向newNode
,随着方法的结束f
和newNode
也会随之失效,最终的效果会是这样。
5.addLast()
list.add("aaa");
list.addFirst("hello");
list.addLast("world");
点击addLast
public void addLast(E e) {
linkLast(e);
}
再点击linkLast
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
先将last
赋值给l
,再将前驱为l
元素值为e
后继为null
的节点赋值给newNode
,这时newNode
为最后一个元素并将自己与前一个元素相连,因为前面已经添加了两个元素所以l==null
不成立,所以会将l
的后继指向newNode
,随着方法的结束l和newNode
也会消失。最终结果会是这样
6.removeFirst()
list.add("aaa");
list.addFirst("hello");
list.addLast("world");
list.removeFirst();
点击removeFirst
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
首先会将first
保存在节点f
中,再点击unlinkFirst
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
先会将节点f
的元素值和f
的后继保存,再将元素本身和后继设置为null
,因为前面添加了三个元素,所以next==null
不成立,就会将待删除元素下一个节点的前驱设置为空。最后将保存的元素返回。
7.removeLast()
list.add("aaa");
list.addFirst("hello");
list.addLast("world");
list.removeFirst();
list.removeLast();
点击removeLast
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
先将last
节点保存,点击unlinkLast
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
将节点的元素值和元素的前驱进行保存,再将节点本身和前驱设置为null
,因为前面有元素所以前驱不为空,所以会将自己的前一个元素的后继设置为空,这样就与上一个元素断开了连接,最后将保存的元素返回。