初始化

构造方法是个无参方法 + 有初始化数据集合参数的方法

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

内部有一个头节点、一个尾节点,以及一个 size 变量记录长度,每个节点记录了后续节点、前缀节点,双向链表

  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. }
  11. transient int size = 0;
  12. transient Node<E> first;
  13. transient Node<E> last;

size()

直接返回 size 变量值

isEmpty()

判断 size == 0

contains(Object o)

判断 indexOf(o) != -1,indexOf(o) 逻辑就是简单的链表遍历

  1. public int indexOf(Object o) {
  2. int index = 0;
  3. if (o == null) {
  4. for (Node<E> x = first; x != null; x = x.next) {
  5. if (x.item == null)
  6. return index;
  7. index++;
  8. }
  9. } else {
  10. for (Node<E> x = first; x != null; x = x.next) {
  11. if (o.equals(x.item))
  12. return index;
  13. index++;
  14. }
  15. }
  16. return -1;
  17. }

add(E e)

调用添加到链表末位方法 linkLast

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

正常添加节点操作,只是判断了下链表是否空的,空的话头节点指向这个节点

remove(Object o)

遍历找到节点后调用 unlink 方法

  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. }

额外判断当前节点是头节点 & 尾节点的情况

addAll(Collection<? extends E> c);

调用了 addAll(size, c)

  1. public boolean addAll(int index, Collection<? extends E> c) {
  2. checkPositionIndex(index);
  3. Object[] a = c.toArray();
  4. int numNew = a.length;
  5. if (numNew == 0)
  6. return false;
  7. Node<E> pred, succ;
  8. if (index == size) {
  9. succ = null;
  10. pred = last;
  11. } else {
  12. succ = node(index);
  13. pred = succ.prev;
  14. }
  15. for (Object o : a) {
  16. @SuppressWarnings("unchecked") E e = (E) o;
  17. Node<E> newNode = new Node<>(pred, e, null);
  18. if (pred == null)
  19. first = newNode;
  20. else
  21. pred.next = newNode;
  22. pred = newNode;
  23. }
  24. if (succ == null) {
  25. last = pred;
  26. } else {
  27. pred.next = succ;
  28. succ.prev = pred;
  29. }
  30. size += numNew;
  31. modCount++;
  32. return true;
  33. }

就是构建新链表插入的过程,只不过区分了是末位插入,还是中间插入

addAll(int index, Collection<? extends E> c)

就是上面的分析过程

clear()

  1. public void clear() {
  2. // Clearing all of the links between nodes is "unnecessary", but:
  3. // - helps a generational GC if the discarded nodes inhabit
  4. // more than one generation
  5. // - is sure to free memory even if there is a reachable Iterator
  6. for (Node<E> x = first; x != null; ) {
  7. Node<E> next = x.next;
  8. x.item = null;
  9. x.next = null;
  10. x.prev = null;
  11. x = next;
  12. }
  13. first = last = null;
  14. size = 0;
  15. modCount++;
  16. }

遍历置空,非必须,为了更好的GC,然后首尾节点置空

get(int index)

调用 node(index),执行查找 index 位置节点的逻辑

  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 的位置,决定是从前往后遍历,还是从后往前遍历

set(int index, E element)

  1. public E set(int index, E element) {
  2. Node<E> x = node(index);
  3. E oldVal = x.item;
  4. x.item = element;
  5. return oldVal;
  6. }

也是先查找节点,然后替换数据

add(int index, E element)

根据 index 的位置执行不同的逻辑

  1. public void add(int index, E element) {
  2. checkPositionIndex(index);
  3. if (index == size)
  4. linkLast(element);
  5. else
  6. linkBefore(element, node(index));
  7. }

linkLast 插入到末尾

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

linkBefore 先找到节点,再插入到前面

  1. void linkBefore(E e, Node<E> succ) {
  2. // assert succ != null;
  3. final Node<E> pred = succ.prev;
  4. final Node<E> newNode = new Node<>(pred, e, succ);
  5. succ.prev = newNode;
  6. if (pred == null)
  7. first = newNode;
  8. else
  9. pred.next = newNode;
  10. size++;
  11. modCount++;
  12. }

remove(int index)

unlink ,node 查找逻辑上文已经分析了

  1. public E remove(int index) {
  2. checkElementIndex(index);
  3. return unlink(node(index));
  4. }

indexOf(Object o)

就是简单的遍历记录 index 位置,找到后返回 index 值