Java Collection LinkedList 源码分析

210 阅读3分钟

LinkedList

细节:
  • 实现方式: 双端链表,可以模拟队列和栈行为
  • 允许元素为Null
  • 列表中的操作将从列表的开头或结尾开始遍历,接近指定索引
  • 非线程安全,如果多个线程并发访问,最新的线程修改了线程的结构,必须使用客户端加锁的方式进行同步(结构修改是添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改)
  • 当创建完迭代器之后,使用了Iterator以外的操作(add | remove)对结构进行了修改,会抛出ConcurrentModificationException
成员变量:
transient Node<E> first;  //头节点
transient Node<E> last;   //尾节点


//节点对象,成员变量包含了上一个节点、下一个节点、泛型数据
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;
        }
}
方法:
  1. 将元素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 = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

  1. 将元素E添加至链表末端,该方法等同于add(E e),也是add方法实际的调用
public void addLast(E e) {
    linkLast(e);
}

    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
        	//这是一个元素为null的链表,设置新节点
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
  1. 在非空节点succ之前,插入节点e
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++;
}
  1. 移除头节点 , 移除尾节点同理
public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        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)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }
  1. 删除节点

    public boolean remove(Object o) {
            if (o == null) {
            	//如果要删除的元素是Null,遍历找到链表中元素为Null的节点,进行删除操作
                for (Node<E> x = first; x != null; x = x.next) {
                    if (x.item == null) {
                        unlink(x);
                        return true;
                    }
                }
            } else {
            	// 否则找到相同元素,进行删除
                for (Node<E> x = first; x != null; x = x.next) {
                    if (o.equals(x.item)) {
                        unlink(x);
                        return true;
                    }
                }
            }
            return false;
        }
    
    //取消节点关系
    E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;
    
    	//如果unlink的是头节点
        if (prev == null) {
            first = next;
        } else {
        	// A => B => C   等价于  A => C
            prev.next = next;
            x.prev = null;
        }
    
    	//如果删除的是尾节点
        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }
    
        x.item = null;
        size--;
        modCount++;
        return element;
    }
    
  2. 返回头节点 | 尾节点的元素

    /**
    * Returns the first element in this list.
    *
    * @return the first element in this list
    * @throws NoSuchElementException if this list is empty
    */
    public E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }

    /**
    * Returns the last element in this list.
    *
    * @return the last element in this list
    * @throws NoSuchElementException if this list is empty
    */
    public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
    }
  1. 返回指定元素的下标

    //正序遍历
    public int indexOf(Object o) {
            int index = 0;
            if (o == null) {
                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;
        }
        
    //倒序遍历
    public int lastIndexOf(Object o) {
            int index = size;
            if (o == null) {
                for (Node<E> x = last; x != null; x = x.prev) {
                    index--;
                    if (x.item == null)
                        return index;
                }
            } else {
                for (Node<E> x = last; x != null; x = x.prev) {
                    index--;
                    if (o.equals(x.item))
                        return index;
                }
            }
            return -1;
        }
    
队列行为:
  1. 查看首个元素,不会移除首个元素,如果队列是空的就返回null
public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}
  1. 将首个元素从队列中弹出,如果队列是空的,就返回null
public E poll() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);// unlinkFirst 移除了该元素
}
  1. 查看首个元素,不会移除首个元素,如果队列是空的就抛出异常NoSuchElementException

    public E element() {
        return getFirst();
    }
    
栈行为:
  1. 将元素压入此列表表示的堆栈

    public void push(E e) {
        addFirst(e);
    }
    
  2. 从此列表表示的堆栈中弹出一个元素。 换句话说,删除并返回此列表的第一个元素。如果堆栈为空则抛出NoSuchElementException

    public E pop() {
        return removeFirst();
    }
    
拷贝:
public Object clone() {
    LinkedList<E> clone = superClone();

    // 设置克隆对象的“状态”
    clone.first = clone.last = null;
    clone.size = 0;
    clone.modCount = 0;

    // 浅拷贝只会拷贝对象,不会克隆里面的元素,所以遍历元素到克隆对象
    for (Node<E> x = first; x != null; x = x.next)
        clone.add(x.item);

    return clone;
}


//
private LinkedList<E> superClone() {
    try {
    	return (LinkedList<E>) super.clone();
    } catch (CloneNotSupportedException e) {
    	throw new InternalError(e);
    }
}