JAVA集合源码解析——LinkedList

1.数据结构

LinkedList的数据结构是一个双向链表结构, next指向下一个节点的地址,prev指向上一节点,element代表链表中的值;同时first节点中的prev和last节点的next为null。

2.LinkedList类中的全局变量

public class LinkedList< E>
        extends AbstractSequentialList< E>
        implements List< E> Deque< E> Cloneable java.io.Serializable {
    /**
     * 链表中实际元素的个数
     */
    transient int  size 0 ;

    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     * (first.prev == null && first.item != null)
     * 链表中的头结点
     */
    transient Node< Efirst ;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     * (last.next == null && last.item != null)
     * 链表中的尾节点
     */
    transient Node< Elast ;
}

3.构造方法(初始化一个链表)

(1).无参构造函数(构造一个空链表)
/**
 * Constructs an empty list.
 * 无参构造函数,构造一个空列表
 */
public  LinkedList() {
}

(2).有参构造函数(将指定集合中的元素构建成LinkedList链表)
/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 * 有参构造函数,将集合c中的各个元素构建成LinkedList链表.
 *
 *  @param  the collection whose elements are to be placed into this list 需要放入链表中的集合
 *  @throws  NullPointerException if the specified collection is null 如果指定添加的集合为空,抛出空指针异常
 */
public  LinkedList(Collection<?  extends  E> c) {
    //调用无参的构造函数,构建一个空列表
    this() ;
    //将集合c中的元素添加到构建的空列表中
    addAll(c) ;
}

4.LinkedList中核心方法

(1). class Node<E>;
/**
 * LinkedList中构成链表的核心源码(链表节点属性)
 */
private static class Node< E> {
    //节点的数据
    item ;
    //指向的下一个节点
    Node< Enext ;
    //指向的上一个节点
    Node< Eprev ;

    //节点的构造方法
    Node(Node< E> prev element Node< E> next) {
        this. item = element ;
        this. next = next ;
        this. prev = prev ;
    }
}

(2). add(E  e);
/**
 * Appends the specified element to the end of this list.
 * 将指定的元素追加到列表的末尾.
 *  <p>
  <p> This method is equivalent to { @link  #addLast}.
 *
 *  @param  element to be appended to this list 需要添加到列表的元素e
 *  @return  { @code  true} (as specified by { @link  Collection#add})
 */
public boolean  add(E e) {
    //调用linkLast方法添加至末尾
    linkLast(e) ;
    return true;
}

/**
 * Links e as last element.
 * 将e作为链表中的最后一个节点添加到列表中
 *
 *  @param  需要添加的元素
 */
void  linkLast(E e) {
    //l赋值last(当前列表的最后一个节点);即为e添加后的首节点
    final LinkedList.Node<E> l = last ;
    //调用new Node<>()初始化当前节点,prev为l;e为节点的数据;因为添加到最后一个节点所以null表示该节点的next
    final LinkedList.Node<E> newNode =  new LinkedList.Node<>(l e , null) ;
    //添加后newNode就成为最后一个节点了所以last赋值为newNode
    last = newNode ;
    if (l ==  null)
        //如果l即该链表的最后一个节点为null,那么新加的节点就是第一个节点需要给first赋值newNode
        first = newNode ;
    else
        //如果添加之前的最后一个节点为不为null,那么新增之前的最后一个节点的next就要指向当前新增的节点newNode
        l. next = newNode ;
    //新增一个节点,链表的大小size++
    size++ ;
    modCount++ ;
}

(3). addAll(Collection<?  extends  E>  c);
/**
 * Appends all of the elements in the specified collection to the end of
 * this list, in the order that they are returned by the specified
 * collection's iterator.  The behavior of this operation is undefined if
 * the specified collection is modified while the operation is in
 * progress.  (Note that this will occur if the specified collection is
 * this list, and it's nonempty.)
 * 将指定集合中的所有元素追加到列表的末尾
 *
 *  @param  collection containing elements to be added to this list 要添加到此列表的元素的集合
 *  @return  { @code  true} if this list changed as a result of the call
 *  @throws  NullPointerException if the specified collection is null 如果c为null抛出空指针异常
 */
public boolean  addAll(Collection<?  extends E> c) {
    return addAll(size c) ;
}

/**
 * Inserts all of the elements in the specified collection into this
 * list, starting at the specified position.  Shifts the element
 * currently at that position (if any) and any subsequent elements to
 * the right (increases their indices).  The new elements will appear
 * in the list in the order that they are returned by the
 * specified collection's iterator.
 * 将指定集合中的所有元素插入到该列表中,从指定位置开始
 *
 *  @param  index  index at which to insert the first element
 *              from the specified collection 从指定集合插入第一个元素的索引。
 *  @param  c      collection containing elements to be added to this list 要添加到此列表的元素的集合
 *  @return  { @code  true} if this list changed as a result of the call
 *  @throws  IndexOutOfBoundsException { @inheritDoc }  索引越界异常
 *  @throws  NullPointerException      if the specified collection is null 如果要添加的集合为null抛出空指针异常
 */
public boolean  addAll( int index Collection<?  extends E> c) {
    //检查指定位置索引是否满足条件
    checkPositionIndex(index) ;
    //将要添加到链表的集合转换为Object数组赋值给a
    Object[] a = c.toArray() ;
    //numNew代表要添加集合的长度
    int numNew = a. length ;
    if (numNew ==  0) //如果要添加的集合为空直接返回false
        return false;
    //定义两个临时节点,pred标识要插入集合的前一个节点;succ标识要插入集合的后一个节点
    Node<E> pred succ ;
    if (index == size) { //如果index=size;当链表为空例如构造函数初始化时 或者 在链表结尾添加 走这边
        //如果插入链表为空或者在链表尾部插入;succ(标识要插入集合的后一个节点)一定为空
        succ =  null;
        //如果插入链表为空last为空 pred = null;如果不为空在链表尾部插入pred(标识要插入集合的前一个节点)为链表的最后一个元素last
        pred = last ;
   else { //如果在链表元素中间插入集合
        //succ赋值为当前指定索引节点;node方法根据节点所以获取节点信息
        succ = node(index) ;
        //pred为succ节点的prev
        pred = succ.prev ;
    }
    for (Object o : a) { //遍历要插入的集合
        @SuppressWarnings( "unchecked") E e = (E) o ; //将o的值赋给e
        //初始化当前需要添加的节点newNode;新节点prev = pred, 添加的元素e, next暂时赋值为null
        Node<E> newNode =  new Node<>(pred e , null) ;
        if (pred ==  null) //如果要插入元素的前一个节点为null
            //当前节点就是第一个节点first赋值为当前节点
            first = newNode ;
        else
            //否则pred(要插入元素的前一个节点)的next为当前节点
            pred.next = newNode ;
        //最后添加完节点后当前节点为下次插入时的pred(标识要插入集合的前一个节点)
        pred = newNode ;
    }
    if (succ ==  null) { //标识要插入的后一个节点为null
        //此时的pred就是链表中的最后一个节点
        last = pred ;
   else {
        //要添加的集合的最后一个节点对象的next指向要插入链表的最后一个节点
        pred.next = succ ;
        //同理要插入链表的最后一个节点对象的prev指向pred
        succ.prev = pred ;
    }
    //修改链表元素的大小值+要添加元素的集合大小
    size += numNew ;
    modCount++ ;
    return true;
}

/**
 * 检查指定位置索引是否满足条件
 *
 *  @param  index  从指定集合插入第一个元素的索引。
 */
private void  checkPositionIndex( int index) {
    if (!isPositionIndex(index))
        //调用isPositionIndex判断索引是否满足条件,如果不满足条件抛出该索引越界异常
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index)) ;
}

/**
 * Tells if the argument is the index of a valid position for an
 * iterator or an add operation.
 * 判断参数是否是有效位置的索引
 */
private boolean  isPositionIndex( int index) {
    //如果索引大于等于0并且小于等于size(该链表的大小)返回true
    return index >=  && index <= size ;
}

(4). remove(Object o);
/**
 * Removes the first occurrence of the specified element from this list,
 * if it is present.  If this list does not contain the element, it is
 * unchanged.  More formally, removes the element with the lowest index
 * { @code  i} such that
 *  <tt> (o==null &nbsp; ? &nbsp; get(i)==null &nbsp; : &nbsp; o.equals(get(i))) </tt>
  * (if such an element exists).  Returns { @code  true} if this list
 * contained the specified element (or equivalently, if this list
 * changed as a result of the call).
 * 找到要移除元素的值,没找到什么都不用做,如果存在多个一样的值则移除索引index最小的那个
 *
 *  @param  element to be removed from this list, if present   要移除的元素
 *  @return  { @code  true} if this list contained the specified element
 */
public boolean  remove(Object o) {
    if (o ==  null) { //LinkedList放null,如果要移除的元素为null
        for (Node<E> x = first x !=  null; x = x.next) { //遍历链表
            //如果链表元素中的值为null
            if (x.item ==  null) {
                //调用unlink方法移除
                unlink(x) ;
                return true;
            }
        }
    }  else { //移除非空的元素
        for (Node<E> x = first x !=  null; x = x.next) { //遍历链表
            if (o.equals(x.item)) { //如果链表中的值和要移除的元素相等
                //调用unlink方法移除
                unlink(x) ;
                return true;
            }
        }
    }
    //如果链表中没有找到要移除的元素则返回false
    return false;
}

/**
 * Unlinks non-null node x.
 * 移除指点的节点元素(不能传一个null值)
 */
unlink(Node<E> x) {
    // assert x != null;
    //节点的数据
    final E element = x.item ;
    //该节点的下一个节点
    final Node<E> next = x.next ;
    //该节点的上一个节点
    final Node<E> prev = x.prev ;

    if (prev ==  null) { //如果该节点prev为null
        //该节点就是首节点,删除该节点next就为首节点
        first = next ;
   else { //如果该节点prev不为空
        //该节点的prev.next指向next
        prev.next = next ;
        //该节点的prev指向置空
        x.prev =  null;
    }

    if (next ==  null) { //如果该节点next为null
        //要删除的节点为尾节点,删除该节点后prev就为尾节点
        last = prev ;
   else { //如果该节点next不为null
        //该节点next.prev指向prev
        next.prev = prev ;
        //该节点的next指向置空
        x.next =  null;
    }

    //之前的操作是吧要删除的节点前后指向都置空了,这里吧里面的数据也置空
    x.item =  null;
    //删除后链表的大小--
    size-- ;
    modCount++ ;
    //返回已经删除节点的数据
    return element ;
}

(5). remove(int  index);
/**
 * Removes the element at the specified position in this list.  Shifts any
 * subsequent elements to the left (subtracts one from their indices).
 * Returns the element that was removed from the list.
 * 删除该列表中指定位置的元素。
 *
 *  @param  index  the index of the element to be removed  要删除元素的索引
 *  @return  the element previously at the specified position 返回删除元素的值
 *  @throws  IndexOutOfBoundsException { @inheritDoc } 抛出数组越界异常
 */
public  remove( int index) {
    //检查索引看是否存在索引越界异常
    checkElementIndex(index) ;
    //直接根据索引调用node方法获取节点后调用unlink方法删除该节点
    return unlink(node(index)) ;
}

(6). set(int  index,  E  element);
/**
 * Replaces the element at the specified position in this list with the
 * specified element.
 * 用指定的元素替换列表中指定位置的元素。
 *
 *  @param  index    index of the element to replace 替换元素的索引
 *  @param  element  element to be stored at the specified position 要在指定位置上存储的元素
 *  @return  the element previously at the specified position 替换前该位置上的元素
 *  @throws  IndexOutOfBoundsException { @inheritDoc } 抛出索引越界异常
 */
public  set( int index element) {
    //索引校验
    checkElementIndex(index) ;
    //根据索引值获取该索引上的节点
    Node< E> x = node(index) ;
    //该索引元素替换前的值
    oldVal = x. item ;
    //将替换元素赋给改该节点的item
    x. item = element ;
    //返回该索引元素替换前的值
    return oldVal ;
}

(7). get(int  index);
/**
 * Returns the element at the specified position in this list.
 * 返回该列表中指定位置的元素。
 *
 *  @param  index  index of the element to return 返回元素的索引
 *  @return  the element at the specified position in this list  列表中指定位置的元素
 *  @throws  IndexOutOfBoundsException { @inheritDoc } 抛出索引越界异常
 */
public get( int index) {
    //校验index索引看是否存在越界异常
    checkElementIndex(index) ;
    //直接调用node(index)方法获取节点;通过节点的item属性来拿值。关键还是在node()方法上
    return node(index).item ;
}

/**
 * Returns the (non-null) Node at the specified element index.
 * 返回指定索引位置上的节点信息
 */
Node<E>  node( int index) {
    // assert isElementIndex(index);
    if (index < (size >>  1)) { //如果索引在链表的前半段
        Node<E> x = first ;
        for ( int i =  0 i < index i++) //从first头结点开始遍历
            x = x.next ;
        //返回index位置上的节点对象
        return x ;
   else { //如果索引在链表的后半段
        Node<E> x = last ;
        for ( int i = size -  1 i > index i--) //从last尾节点开始遍历
            x = x.prev ;
        //返回index位置上的节点对象
        return x ;
    }
}

5.LinkedList总结

(1). LinkedList本质是一个双向链表,核心是链表上的节点通过Node内部类实现。
(2). 基于双向链表的属性相对于LinkedList在新增,删除操作时只需要调整指针的指向相对ArrayList性能较好。但是在查询方面需要遍历指针位置上的元素性能相对ArrayList来说较差。
(3). 和ArrayList一样都是非线程安全的在单线程下才能使用。
(4). 链表中元素的属性值可以为null。











猜你喜欢

转载自blog.csdn.net/wangshouhan/article/details/80846329
今日推荐