关于LinkedList的简单总结: LinkedList底层维护了一个双向链表 LinkedList中维护了三个属性:first与last与size first指向首节点 last指向尾结点 size表示集合中的元素个数 每个节点(Node)对象中维护了prev、next、item三个属性 prev指向前一个节点 next指向后一个节点 item存放数据 关于元素:LinkedList可以添加任意元素(包括null) 且元素可重复 关于效率:由于LinkedList是通过链表实现的 相较于通过数组实现的ArrayList效率较高
构造方法
无参构造:
public LinkedList() {
}
有参构造:
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
重要属性
LinkedList重要属性:
size:链表中的结点个数
first:指向头结点
last:指向尾结点
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
结点类Node(内部类):
item:存放的数据
next:指向后一个结点
prev:指向前一个结点
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;
}
}
增删源码简析
增(以 public boolean add(E e) 方法为例):
该方法默认将元素链接在链表尾端,故在方法内部调用linkLast方法
public boolean add(E e) {
linkLast(e);
return true;
}
进入linkLast方法:
1.将尾结点的引用,即last,赋值给 l
2.创建一个新结点newNode,该结点将作为新的尾结点。构造方法中的参数分别为prev、item与next:
prev:由于newNode将作为新的尾结点,故prev将指向前尾结点 l
item:存储数据e
next:由于newNode将作为新的尾结点,自然没有后续结点,故next为null
3.将newNode的引用赋值给last,此时last重新指向了尾结点newNode
4.进行判断,已知 l 为原尾结点:
若l == null,即链表中本没有元素,则将first指向尾结点newNode,newNode将一同作为头结点
若l != null,即链表中已存在元素,则将原尾结点 l 的next属性指向尾结点newNode,完成链接
5.进行善后处理,size++与modCount++
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++;
}
删(以 public E remove() 方法为例):
该方法默认删除头结点,故在方法内部调用removeFirst方法
public E remove() {
return removeFirst();
}
进入removeFirst方法,该方法将检测头结点是否为空,是则抛出NoSuchElementException异常,否则调用unlinkFirst方法删除头结点
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
进入unlinkFirst方法:
1.将头结点 f 存储的数据赋值给element,并在方法结束后将其返回
2.将头结点 f 的next属性赋值给next结点,此时next结点指向链表第二个结点(若该结点存在的话)
3.将头结点 f 的item属性与next属性赋值为null(帮助GC,GC即垃圾回收机制),将first指向next结点,即链表的第二个结点(若该结点存在的话)
4.进行判断,已知next指向第二个结点:
若next == null,即链表中不存在第二个结点,换言之链表中只存在一个结点,该结点被删除后链表为空,故将last赋值为null(第三步中已将first指向next结点,此时first亦为null)
若next != null,即链表中存在第二个结点,由于头结点被删除,故第二个结点将成为头结点,故将next结点的prev属性赋值为null
5.进行善后处理,size--与modCount++
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;
}