1. LinkList 概述

LinkedList类是List接口的实现类,它是一个集合,可以根据索引来随机的访问集合中的元素,还实现了Deque接口,它还是一个队列,可以被当成双端队列来使用。虽然LinkedList是一个List集合,但是它的实现方式和ArrayList是完全不同的,ArrayList的底层是通过一个动态的Object[]数组来实现的,而LinkedList的底层是通过链表来实现的,因此它的随机访问速度是比较差的,但是它的删除,插入操作会很快。
image.png

2. LinkList 实现

2.1 构造方法

  1. public LinkedList() {
  2. }
  3. public LinkedList(Collection<? extends E> c) {
  4. this();
  5. addAll(c);
  6. }

LinkedList没有长度的概念,所以不存在容量不足的问题,因此不需要提供初始化大小的构造方法,因此值提供了两个方法,一个是无参构造方法,初始一个LinkedList对象,和将指定的集合元素转化为LinkedList构造方法。

2.2 Node节点

  1. private static class Node<E> {
  2. E item;
  3. Node<E> next;
  4. Node<E> prev;
  5. Node(Node<E> prev, E element, Node<E> next) {
  6. this.item = element;
  7. this.next = next;
  8. this.prev = prev;
  9. }
  10. }

Node 是在 LinkedList 里定义的一个静态内部类,它表示链表每个节点的结构,包括一个数据域 item,一个后置指针 next,一个前置指针 prev。

2.3 add

  1. public boolean add(E e) {
  2. linkLast(e);
  3. return true;
  4. }
  5. void linkLast(E e) {
  6. final Node<E> l = last;
  7. final Node<E> newNode = new Node<>(l, e, null);
  8. last = newNode;
  9. if (l == null)
  10. first = newNode;
  11. else
  12. l.next = newNode;
  13. size++;
  14. modCount++;
  15. }

添加方法默认是添加到LinkedList的尾部,首先将last指定的节点赋值给l节点,然后新建节点newNode ,此节点的前驱指向l节点,data = e , next = null , 并将新节点赋值给last节点,它成为了最后一个节点,根据当前List是否为空做出相应的操作。若不为空将l的后继指针修改为newNodw。 size +1 , modCount+1;modCount: 此列表在结构上被修改的次数

2.4 remove

  1. public boolean remove(Object o) {
  2. if (o == null) {
  3. for (Node<E> x = first; x != null; x = x.next) {
  4. if (x.item == null) {
  5. unlink(x);
  6. return true;
  7. }
  8. }
  9. } else {
  10. for (Node<E> x = first; x != null; x = x.next) {
  11. if (o.equals(x.item)) {
  12. unlink(x);
  13. return true;
  14. }
  15. }
  16. }
  17. return false;
  18. }

从该列表中删除指定元素的第一个匹配项(如果存在)。如果此列表不包含该元素,则它将保持不变。更正式地说,移除具有最低索引i的元素,以便(o==null?get(i)==null:o.equals(get(i))(如果存在这样的元素)。如果此列表包含指定的元素,则返回true(如果此列表因调用而更改,则返回等效值)。

  1. E unlink(Node<E> x) {
  2. // assert x != null;
  3. final E element = x.item;
  4. final Node<E> next = x.next;
  5. final Node<E> prev = x.prev;
  6. if (prev == null) {
  7. first = next;
  8. } else {
  9. prev.next = next;
  10. x.prev = null;
  11. }
  12. if (next == null) {
  13. last = prev;
  14. } else {
  15. next.prev = prev;
  16. x.next = null;
  17. }
  18. x.item = null;
  19. size--;
  20. modCount++;
  21. return element;
  22. }

取消链接非空节点x

2.5 get

  1. public E get(int index) {
  2. checkElementIndex(index);
  3. return node(index).item;
  4. }
  1. Node<E> node(int index) {
  2. // assert isElementIndex(index);
  3. if (index < (size >> 1)) {
  4. Node<E> x = first;
  5. for (int i = 0; i < index; i++)
  6. x = x.next;
  7. return x;
  8. } else {
  9. Node<E> x = last;
  10. for (int i = size - 1; i > index; i--)
  11. x = x.prev;
  12. return x;
  13. }
  14. }

位运算与直接做除法的区别。先将index与长度size的一半比较,如果indexsize/2,就只从位置size往前遍历到位置index处。这样可以减少一部分不必要的遍历

2.5 总结

LinkedList是一个功能很强大的类,可以被当作List集合,双端队列和栈来使用。LinkedList底层使用链表来保存集合中的元素,因此随机访问的性能较差,但是插入删除时性能非常的出色。LinkedList在1.8版本有添加了一点新的内容,添加了一个static final 修饰的内部类LLSpliterator 并实现了Spliterator ,为了实现并行遍历而新添加的功能,整体的变化并不是很大。