java容器体系(三)----List(LinkedList)
LinkedList 是 List 的又一种实现方法,首先看一下它的类图:

LinkedList 继承自 AbstractSequentialList, 实现了Deque、Cloneable、Serializable 接口,同 ArrayList 一样,它包含了AbstractList 的所有的行为特征,但它的实现方式是链表,而且是双向链表。
1、成员变量
LinkedList 提供了四个成员变量
transient int size = 0; // LinkedList 的容量 transient Node<E> first; // 第一个节点 transient Node<E> last; // 最后一个节点 protected transient int modCount = 0; // List结构化修改的次数(size大小发生改变的操作都会增加)
可以看到,四个变量都使用了 transient 进行修饰,在序列化的时候这三个变量不会序列化。
Node 是 LinkedList 的私有内部类,实现代码如下:
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; } }
2、构造函数
public LinkedList() { } public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
LinkedList 提供了两个构造函数,一个是无参数构造函数;另一个是带有 Collection 类型参数的构造函数。可以看到,与ArrayList不同,LinkedList 并不需要设置初始容量。
3、实现自Deque的方法
Deque 是一个队列接口,表明该类的实现类是一个双向队列,实现了 Queue。Queue 提供了 add(E e)、offer(E e)、remove()、poll()、element()、peek() 方法,Deque 提供了addFirst(E e)、addLast(E e)、offerFirst(E e)、offerLast(E e)、removeFirst()、removeLast()、pollFirst()、pollLast()、getFirst()、getLast()、peekFirst()、peekLast()等。
Queue 提供的方法主要是队列头部取出以及尾部的加入方法,是FIFO(先入先出)的数据结构;Deque 在队列的头部和尾部均可以获取、添加、以及删除。下面分析一下具体方法的实现:
(1)add(E e) 方法
public boolean add(E e) { // 在尾部添加一个元素,等同于 addLast(E e) linkLast(e); return true; } void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) // 加入之前,last 未初始化 first = newNode; // 初始化 first,此时first = last else l.next = newNode; size++; // 元素数量+1 modCount++; // 修改次数+1 }
(2)offer(E e) 方法 其实使用的是add方法
public boolean offer(E e) { return add(e); }
(3) remove() 方法
public E remove() { // 删除队列的第一个接地那 return removeFirst(); } public E removeFirst() { final Node<E> f = first; if (f == null) // first 未初始化,表示队列里无数据 throw new NoSuchElementException(); return unlinkFirst(f); } 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) // 即此时first=null时,队列里没有元素,last也置为null last = null; else next.prev = null; // 前驱节点释放 size--; // 队列元素数量-1 modCount++; // 结构化修改数量+1 return element; }
(4)poll() 方法
public E poll() { // 删除队列头部的第一个元素并返回 final Node<E> f = first; return (f == null) ? null : unlinkFirst(f); }
poll() 方法和 remove() 方法差不多,都是使用 unlinkFirst(E e) 删除头部的第一个元素,但是和 remove(E e) 不同的是,在队列为空的情况下调用 poll() 会返回 null,而 remove() 方法会抛出 NoSuchElementException 异常(其实是使用removeFirst(E e) 方法抛出的异常)。
(5)element() 方法
public E element() { // 返回头部节点的元素 return getFirst(); } public E getFirst() { final Node<E> f = first; if (f == null) // 队列为空时,抛出异常 throw new NoSuchElementException(); return f.item; }
(6)peek() 方法
public E peek() { final Node<E> f = first; return (f == null) ? null : f.item; }
peek() 和 element() 方法都是返回队列的头部节点,队列为空时,peek() 会返回 null ,element() 会抛出 NoSuchElementException 异常。
以上是Queue 提供的方法,其实还有 Collection 当中的方法,后面再介绍,下面介绍 Dueue 的方法。
(1)addFirst(E e)
public void addFirst(E e) { // 在队列的头部添加元素 linkFirst(e); } 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,first为null last = newNode; else f.prev = newNode; size++; modCount++; }
(2)addLast(E e)
public void addLast(E e) { // 等同于add(E e)和offer(E e),只是没有返回值 linkLast(e); }
(3)offerFirst(E e)
public boolean offerFirst(E e) { // 等同于addFirst(E e),有返回值 addFirst(e); return true; }
(4)offerLast(E e)
public boolean offerLast(E e) { // 等同于addLast(E e),有返回值 addLast(e); return true; }
(5)push(E e)
public void push(E e) { addFirst(e); }
(6)pop(E e)
public E pop() { // 删除队列头部元素并返回,队列为空会抛出异常 return removeFirst(); }
4、其他方法
(1)get(int index)方法
public E get(int index) { // 获取指定位置的元素 checkElementIndex(index); return node(index).item; } private void checkElementIndex(int index) { if (!isElementIndex(index)) // 判断是否 0<=index<size throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private boolean isElementIndex(int index) { return index >= 0 && index < size; } private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; } Node<E> node(int index) { // 这个才是真正的获取指定位置元素的方法,获取的是引用 // assert isElementIndex(index); if (index < (size >> 1)) { // index < size/2,从头部开始遍历,否则从尾部开始遍历 Node<E> x = first; for (int i = 0; i < index; i++) x = x.next; return x; } else { Node<E> x = last; for (int i = size - 1; i > index; i--) x = x.prev; return x; } }
(2)set(int index,E element)
public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); // 将获取到指定位置的引用返回 E oldVal = x.item; x.item = element; return oldVal; }
(3)add(int index, E element)
public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); // 从尾部添加元素 else // 获取指定位置元素的引用,其前驱节点改为新元素 linkBefore(element, node(index)); } void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
(4)indexOf(Object o)
public int indexOf(Object o) { // 从头部遍历,返回头一个等于输入参数的元素位置 int index = 0; if (o == null) { // 为 null 时,判断元素等于null,否则调用equals判断元素相等 for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; }
(5)itrator() 方法
LinkedList 中本身没有 itrator() 的方法体,方法体在其父类 AbstractSequentialList 中,它实际使用的也是 AbstractList 的实现。
(6)listItrator() 方法
当然 ListedList 作为 AbstractList 的子孙类,同样提供了 listItrator() 方法,既可以向前遍历,也可以向后遍历。其返回类型 Iterator 的实现方式也是内部类:
// 无参数的实现方式在 AbstractList 中已经实现 public ListIterator<E> listIterator(int index) { checkPositionIndex(index); return new ListItr(index); } private class ListItr implements ListIterator<E> { private Node<E> lastReturned; private Node<E> next; private int nextIndex; private int expectedModCount = modCount; ListItr(int index) { // assert isPositionIndex(index); next = (index == size) ? null : node(index); // 下一节点位置 nextIndex = index; } public boolean hasNext() { return nextIndex < size; } public E next() { checkForComodification(); if (!hasNext()) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; return lastReturned.item; } public boolean hasPrevious() { return nextIndex > 0; } public E previous() { checkForComodification(); if (!hasPrevious()) throw new NoSuchElementException(); lastReturned = next = (next == null) ? last : next.prev; nextIndex--; return lastReturned.item; } public int nextIndex() { return nextIndex; } public int previousIndex() { return nextIndex - 1; } public void remove() { checkForComodification(); // 检查expectedModCount 与 modCount 是否相等 if (lastReturned == null) throw new IllegalStateException(); Node<E> lastNext = lastReturned.next; unlink(lastReturned); if (next == lastReturned) next = lastNext; else nextIndex--; lastReturned = null; expectedModCount++; } public void set(E e) { if (lastReturned == null) throw new IllegalStateException(); checkForComodification(); // 检查expectedModCount 与 modCount 是否相等 lastReturned.item = e; } public void add(E e) { checkForComodification(); // 检查expectedModCount 与 modCount 是否相等 lastReturned = null; if (next == null) linkLast(e); else linkBefore(e, next); nextIndex++; expectedModCount++; } public void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (modCount == expectedModCount && nextIndex < size) { action.accept(next.item); lastReturned = next; next = next.next; nextIndex++; } checkForComodification(); } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
(7)descendingIterator() 方法
descendingIterator() 方法是 LinkedList 特有的方法,该方法可以看做将 itrator() 倒过来,方法名称一样,只是倒序遍历
public Iterator<E> descendingIterator() { return new DescendingIterator(); } // 同样的hasNext()/next()名称,却是由后向前遍历 private class DescendingIterator implements Iterator<E> { private final ListItr itr = new ListItr(size()); // LinkedList的内部类 public boolean hasNext() { return itr.hasPrevious(); } public E next() { return itr.previous(); } public void remove() { itr.remove(); } }
(8)clone() 方法
private LinkedList<E> superClone() { try { return (LinkedList<E>) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(e); } } public Object clone() { LinkedList<E> clone = superClone(); // 感觉可以用new LinkedList()的 // Put clone into "virgin" state clone.first = clone.last = null; // first和last 置为空 clone.size = 0; clone.modCount = 0; // 将元素一个一个装入克隆对象 for (Node<E> x = first; x != null; x = x.next) clone.add(x.item); return clone; }
(9)序列化和反序列化方法
前面介绍过 LinkedList 的四个成员变量 first、last、size、modCount 都使用了 transient 修饰,无法被序列化。java 对它们进行了重写。
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out any hidden serialization magic s.defaultWriteObject(); // Write out size s.writeInt(size); // 将 size 写出 // Write out all elements in the proper order. for (Node<E> x = first; x != null; x = x.next) s.writeObject(x.item); // 一个接一个将元素写出 } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden serialization magic s.defaultReadObject(); // Read in size int size = s.readInt(); // 这里可没有对成员变量size赋值 // Read in all elements in the proper order. for (int i = 0; i < size; i++) linkLast((E)s.readObject()); // 内部会进行modCount++,size++操作,因此 modCount=size }

浙公网安备 33010602011771号