java源码-LinkedList

65 阅读2分钟

a4bc79f418374200863fd8b5178fa3c7_tplv-k3u1fbpfcp-watermark.png

继承关系

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
  • 首先继承了AbstractSequentialList<E>该抽象类是抽象顺序访问的list,比如linkedList。为了减少重复代码。
  • 实现了List接口,可以作为一个list使用
  • 实现Deque,可以作为一个双端队列使用
  • 实现Cloneable,这是一个标记接口,说明LinkedList可以被克隆
  • 实现Serializable,标记接口,说明可LinkedList可被序列化

存储结构

//大小
transient int size = 0;
//链表头节点
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;
    }
}

LinkedList的结构就是一个普通的双向链表

image.png

构造方法

public LinkedList()

//没什么好说的,因为空链表的时候都为null值,所以什么都不用做
//链表也没什么扩容的问题
//链表初始容量也不需要设置
public LinkedList() {
}

public LinkedList(Collection<? extends E> c)

//通过集合进行初始化,把集合全部添加到linkedList中
public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
}

//在索引index处添加集合c
public boolean addAll(int index, Collection<? extends E> c) {
    checkPositionIndex(index);
    //获取集合的数组
    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0)
        return false;
    Node<E> pred, succ;
    if (index == size) {
        succ = null;
        pred = last;
    } else {
        succ = node(index);
        pred = succ.prev;
    }
    //遍历输入集合所有元素
    for (Object o : a) {
        //创建新节点
        @SuppressWarnings("unchecked") E e = (E) o;
        Node<E> newNode = new Node<>(pred, e, null);
        //添加节点
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }
    
    //连接
    if (succ == null) {
        last = pred;
    } else {
        pred.next = succ;
        succ.prev = pred;
    }
    
    size += numNew;
    modCount++;
    return true;
}

重要方法

add(E e)

//实现的是List<>的接口方法
public boolean add(E e) {
    linkLast(e);
    return true;
}

linkLast(E e)

void linkLast(E e) {
    //保存旧的尾节点
    final Node<E> l = last;
    //创建节点,并把prev指向尾节点
    final Node<E> newNode = new Node<>(l, e, null);
    //更新尾节点为新节点
    last = newNode;
    //如果为空,新节点设置为头节点
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

get(int index)

public E get(int index) {
    //检验index是否在[0-n)之间
    checkElementIndex(index);
    return node(index).item;
}

node(int index)

Node<E> node(int index) {
    if (index < (size >> 1)) {
        //index如果小于size一半,从头开始遍历
        Node<E> x = first;
        for (int i = 0; i < index; i++)
            x = x.next;
        return x;
    } else {
        //index如果大于size一半,从尾开始遍历
        Node<E> x = last;
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

add(int index, E element)

public void add(int index, E element) {
    checkPositionIndex(index);
  
    if (index == size)、
        //如果是添加到尾部,直接添加即可
        linkLast(element);
    else
        //先获取需要插入的节点位置,然后调用linkBefore进行插入
        linkBefore(element, node(index));
}

linkBefore(E e, Node node)

void linkBefore(E e, Node<E> succ) {
    //暂存当前节点上一个节点
    final Node<E> pred = succ.prev;
    //创建新节点同时,将新节点的prev指向上一节点,next指向succ
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        //添加位置刚好是头节点,设置新头节点
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}

先放这么多,其他就不放出来了。不过linkedList的代码还是非常简洁的,大佬不愧是大佬。