LinkedList源码学习

Posted moseast

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LinkedList源码学习相关的知识,希望对你有一定的参考价值。

一、类与成员变量

public class LinkedList<E> extends AbstractSequentialList<E>
                implements List<E>, Deque<E>, Cloneable, java.io.Serializable

LinkedList继承自AbstractSequentialList抽象类,实现了List<E>DequeCloneableSerializable接口。

其中:

DequeQueue的子接口是双向队列,它支持从两个端点方向检索和插入元素

实现Cloneable接口的类的对象允许被克隆。同时该类需要重写Object类的clone方法。

实现Serializable接口,即采用了Java默认的序列化机制。

 

private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;

 

header是双向链表的头节点,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。 
size是双向链表中节点实例的个数。、

其中Entry类的源码

 

private static class Entry<E> {
   E element;
    Entry<E> next;
    Entry<E> previous;

    Entry(E element, Entry<E> next, Entry<E> previous) {
        this.element = element;
        this.next = next;
        this.previous = previous;
   }
}

 

节点类很简单,element存放业务数据,previousnext分别存放前后节点的信息(在数据结构中我们通常称之为前后节点的指针)。

 

二、构造:

public LinkedList() {
    header.next = header.previous = header;
}
public LinkedList(Collection<? extends E> c) {
    this();
   addAll(c);
}

 

 

三、操作LinkedList

添加

    private Entry<E> entry(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        Entry<E> e = header;
        if (index < (size >> 1)) {
            for (int i = 0; i <= index; i++)
                e = e.next;
        } else {
            for (int i = size; i > index; i--)
                e = e.previous;
        }
        return e;
    }

 

 

public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
}
// index参数指定collection中插入的第一个元素的位置
public boolean addAll(int index, Collection<? extends E> c) {
    // 插入位置超过了链表的长度或小于0,报IndexOutOfBoundsException异常
    if (index < 0 || index > size)
        throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
    Object[] a = c.toArray();
   int numNew = a.length;
   // 若需要插入的节点个数为0则返回false,表示没有插入元素
    if (numNew==0)
        return false;
    modCount++;//否则,插入对象,链表修改次数加1
    // 保存index处的节点。插入位置如果是size,则在头结点前面插入,否则在获取index处的节点插入
    Entry<E> successor = (index==size ? header : entry(index));
    // 获取前一个节点,插入时需要修改这个节点的next引用
    Entry<E> predecessor = successor.previous;
    // 按顺序将a数组中的第一个元素插入到index处,将之后的元素插在这个元素后面
    for (int i=0; i<numNew; i++) {
        // 结合Entry的构造方法,这条语句是插入操作,相当于C语言中链表中插入节点并修改指针
        Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);
        // 插入节点后将前一节点的next指向当前节点,相当于修改前一节点的next指针
        predecessor.next = e;
        // 相当于C语言中成功插入元素后将指针向后移动一个位置以实现循环的功能
        predecessor = e;
  }
    // 插入元素前index处的元素链接到插入的Collection的最后一个节点
    successor.previous = predecessor;
    // 修改size
    size += numNew;
    return true;
}

 

    private Entry<E> addBefore(E e, Entry<E> entry) {
        Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
        newEntry.previous.next = newEntry;
        newEntry.next.previous = newEntry;
        size++;
        modCount++;
        return newEntry;
    }    

    public boolean add(E e) {
    addBefore(e, header);
        return true;
    }
    public void add(int index, E element) {
        addBefore(element, (index==size ? header : entry(index)));
    }


    public void addFirst(E e) {
        addBefore(e, header.next);
    }

    public void addLast(E e) {
        addBefore(e, header);
    }   

 

以上是关于LinkedList源码学习的主要内容,如果未能解决你的问题,请参考以下文章

LinkedList源码学习

LinkedList源码解析学习

LinkedList源码学习

Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例

Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例

集合-LinkedList源码解析