LinkedList源码分析

ArrayList与LinkedList简洁对比:

ArrayList是查询速度比较快,插(插入中间,而不是末尾)删速度比较慢,而LinkedList就是查询速度比较慢,插(插入中间)删速度比较快,到底是什么原因导致了它们的不一样呢?了解过它们的底层实现,就可以知道,ArrayList底层是由数组实现的,数组就是在内存里面申请一段连续的内存,然后在里面读写数据,它查询的时间复杂度是O(1),但是如果要往数组里面添加或者删除数据的话,在添加(删除)位置后面数都要往前或者往后相应的位置,所以它增删的时间复杂度是O(n)。然而,LinkedList的底层是由链表实现的,而链表查询数据的时间复杂度是O(n),而增删数据的时间复杂度是O(1)。由此可见,它们在查询和增删数据两个维度上有着不同的差异,所以在具体使用时,可以根据自己的需要选择不同的数据结构。

如果仅仅是简单的放进去,然后取出来,用ArrayList,效率更高一些!

//源码中LinkedList类的声明
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{

源码注解:

⑴、LinkedList(双链列表)同时实现了接口List和Deque(LinkedList实现了这两个接口的所有方法),它既是一个链表,也是一个双端队列。它允许添加任何元素,包括null元素。
⑵、LinkedList所有方法的实现都体现了双链表的特性,所有有关索引的操作都自动从LinkedList的开头或结尾开始遍历(如果索引更接近开头,自动从开头开始遍历,更接近结尾,自动从结尾开始遍历)。
⑶、LinkedList不是线程安全的,如果在多线程环境中涉及结构修改(结构修改是指添加或删除一个或多个元素),必须从外部保证LinkedList的线程安全(通过对持有LinkedList的对象进行同步来完成)。如果不存在持有LinkedList的对象,应该使用类Collections的方法synchronizedList(new LinkedList(…)),具体的代码如下:

List list = Collections.synchronizedList(new LinkedList(...));

最好在创建LinkedList对象时就这么做,以防止任何不安全的操作发生。
⑷、在获取了迭代器或列表迭代器后,除非使用它们自身提供的方法(方法remove()和add())修改LinkedList的结构,否则都将抛出ConcurrentModificationException异常(快速失败机制)。迭代器不会在未来的不确定时间内冒任意不确定行为的风险(如果在多线程环境的迭代过程中修改了LinkedList的结构,可能返回很多种结果)。
⑸、注意,无法保证快速失败机制一定会执行,只能说迭代器会尽最大的努力抛出ConcurrentModificationException异常。因此,通过快速失败机制保证程序的正确性是错误的,它通常只能用于检测错误。

节点的图示:
LinkedList中的每个节点都是一个单独的存储空间,"元素"存储在节点中,但节点中不仅只有元素。ArrayList的底层是数组,数组是连续的存储空间(通过持有数组的引用+"[ 索引 ]"+访问),所以每个存储空间只需存储元素,不需要存储相互之间的关系。而LinkedList底层是链表(双向),链表不是连续的存储空间,所以每个存储空间(节点)不仅需要存储元素,还需要存储相互之间的关系(prev:上一个节点的位置,如果有。next:下一个节点的位置,如果有)。

链表的图示:
在链表中,一个独立的存储空间就是一个节点,同时,一个节点就是一个内部类Node的对象实例。链表是由若干个节点构成的,

内部类Node的源码:

    //链表节点的类型
    //一个对象对应一个节点
    private static class Node<E> {
       //元素的引用
       //如果为null,表示没有存储任何元素,如果不为null,表示存储了某种类型的元素
       E item;
       //下一个节点的引用
       //引用代表了对象的十六进制地址值,所以也可以注释为:下一个节点在内存中的地址
       //如果为null,可能是空链表,也可能是尾节点
       Node<E> next;
       Node<E> prev;
       Node(Node<E> prev, E element, Node<E> next) {
          //元素的引用初始化
          this.item = element;
          //上一个节点的引用初始化
          this.next = next;
          //下一个节点的引用初始化
          this.prev = prev;
       }
    }

 变量

size

//元素的数量,初始化为0
//关键字transient表示它不能被序列化
transient int size = 0;

first

//首节点的固定引用(方便节点的创建、添加和链表的查找遍历)
//链表必须先创建添加首节点,才能创建添加第二个节点,以此类推
//查找遍历同理,链表是顺序访问列表,只能从开头或者末尾开始挨个访问
//所以首节点不可能匿名,需要一个固定引用方便后续的使用
//关键字transient表示它不能被序列化
transient Node<E> first;

last

//尾节点的固定引用(方便节点的查找遍历)
//关键字transient表示它不能被序列化
transient Node<E> last;

构造器

LinkedList()

 //构造方法,创建一个没有任何节点的空LinkedList
 public LinkedList() {}

LinkedList(Collection<? extends E> c)

    //构造方法,创建这样一个LinkedList
    //①、节点数量与指定集合c的元素数量一致
    //②、指定集合c中的每个元素都存储在对应索引值的节点中
    //换句话说就是:节点的顺序与指定集合c的元素顺序完全一致
    public LinkedList(Collection<? extends E> c) {
       //调用无参构造函数,如果它在后期的Java
       //升级版本中发生修改,可以实时与它保持一致
       //保证了程序的可扩展性,方便了后期的代码维护
       this();
       //通过方法addAll(Collection<? extends E> c)
       //添加c的所有元素
       addAll(c);
    }

linkFirst(E e) 

    //创建一个包含元素e的新节点
    //并链接至链表的首部(linkFirst),这个节点就是链表的新首节点
    //方法存在的意义:LinkedList同时implement了接口Queue和Deque
    private void linkFirst(E e) {
       //假设链表不为空,获取并传递首节点的引用
       //传递后,引用f和first同时指向首节点
       //这一步实际上也是复制首节点的引用
       final Node<E> f = first;
       //分别提供以下参数创建一个节点对象newNode:
       //①、上一个节点的引用null
       //②、元素e
       //③、下一个节点的引用f
       //newNode其实就是新的首节点,两点原因:
       //①、在链表中,只有首节点的上一个节点引用为null
       //②、原首节点f成为newNode的下一个节点
       //③、节点关系的维护放在了构造函数中(参考截图)
       final Node<E> newNode = new Node<>(null, e, f);
       //将newNode赋值给first,保证first永远都是首节点的引用
       first = newNode;
       //上面的代码只初始化了first,并未初始化last
       //如果首节点f为null,说明链表为空
       //所以新创建的节点newNode既是首节点也是尾节点
       if (f == null)
          //初始化last
          last = newNode;
       else
          //如果首节点f不为空
          //需要考虑两方面:元素和关系
          //元素由客户端程序员添加
          //这里只需考虑关系
          //首节点f的prev肯定为null
          //现在创建了新的首节点newNode
          //f自然就是第二节点
          //所以需要通过代码表示:
          //f的上一个节点是newNode
          //以此保证各个节点的关系正确
          f.prev = newNode;
       //新增一个节点,长度+1
       size++;
       //继承自抽象类AbstractList,保证快速失败机制的正常执行
       //新增节点是结构性修改
       modCount++;
    }

linkLast(E e)

    //创建一个包含元素e的新节点,并链接至链表的尾部(linkLast)
    //这个节点就是链表的新尾节点
    //方法存在的意义:LinkedList同时implement了接口Queue和Deque
    //实现它们的方法时可以有效避免代码重复 
    void linkLast(E e) {
       //假设链表不为空,获取并传递尾节点的引用
       //传递后,引用l和last同时指向尾节点
       //这一步实际上也是复制尾节点的引用
       final Node<E> l = last;
       //创建一个节点对象newNode://①、上一个节点的引用l②、元素e
       //③、下一个节点的引用null
       //newNode其实就是新的尾节点,两点原因:
       //①、在链表中,只有尾节点的下一个节点引用为null
       //②、原尾节点l成为newNode的上一个节点
       final Node<E> newNode = new Node<>(l, e, null);
       //将newNode赋值给last,保证last永远都是尾节点的引用
       last = newNode;
       //上面的代码只初始化了last,并未初始化first
       //如果尾节点l为null,说明链表为空
       //所以新创建的节点newNode既是尾节点也是首节点
       if (l == null)
          //初始化first
          first = newNode;
       else
          //如果尾节点l不为空
          //需要考虑两方面:元素和关系
          //元素由客户端程序员添加
          //这里只需考虑关系
          //尾节点l的next肯定为null
          //现在创建了新的尾节点newNode
          //l自然就是倒数第二节点
          //所以需要通过代码表示:
          //l的下一个节点是newNode
          //以此保证各个节点的关系正确
          l.next = newNode;
       //新增一个节点,长度+1
       size++;
       //继承自抽象类AbstractList,保证快速失败机制的正常执行
       modCount++;
    }

linkBefore(E e, Node< E > succ)

    //创建一个包含指定元素e的节点
    //并将它链接在指定节点succ之前(linkBefore)
    void linkBefore(E e, Node<E> succ) {
        //获取节点succ的上一个节点
        final Node<E> pred = succ.prev;
        //分别提供以下参数创建一个节点对象newNode:
        //①、上一个节点的引用pred
        //②、元素e
        //③、下一个节点的引用succ
        final Node<E> newNode = new Node<>(pred, e, succ);
        //创建后还需要维护节点之间的关系
        //以保证newNode是succ的上一个节点
        succ.prev = newNode;
        //---------------下面需要考虑一些其它情况
        //如果pred为null,说明succ是链表的首节点
        //(只有首节点的上一个节点为null)
        //既然是首节点,那么就还有另一个固定的引用first
        if (pred == null)
           //newNode代替了succ成为新的首节点
           //需要对first重新进行初始化,保证first永远都是首节点的引用
           first = newNode;
        //如果pred不为null
        //上面的代码只维护了newNode → succ方向的关系
        //(succ.prev = newNode)
        //LinkedList是双向的
        //所以,还需要维护pred → newNode方向的关系
        else
           //newNode是pred的下一个节点
           pred.next = newNode;
        //新增一个节点,长度+1
       size++;
       //继承自抽象类AbstractList,保证快速失败机制的正常执行
       //新增节点是结构性修改
       modCount++;
    }

unlinkFirst(Node< E > f)

    //在指定节点f处将链表一分为二
    //链表左边直接丢弃(包含节点f)
    //链表右边是新的链表
    private E unlinkFirst(Node<E> f) {
        //获取节点f的元素
        final E element = f.item;
        //获取节点f的下一个节点
        final Node<E> next = f.next;
        //清空节点f的元素
        f.item = null;
        //断开节点f与下一个节点的关系
        //在这里将链表一分为二
        //链表左边直接丢弃(包含节点f)
        f.next = null; 
        //链表右边的首节点
        //也就是节点f的下一个节点next
        //成为新链表的首节点
        //需要对first重新进行初始化
        //保证first永远都是首节点的引用
        first = next;
        //---------------下面需要考虑一些其它情况
        //如果next为null,说明新链表为null
        if (next == null)
           //那么新链表的尾节点也是null
           //需要对last重新初始化
           last = null;
        //如果next不为null,它就是新链表的首节点
        //上面的代码只断开了f → next方向的关系
        //(f.next = null)
        //LinkedList是双向的
        //所以,还需要断开next → f方向的关系
        else
           next.prev = null;
           //同时,首节点的上一个节点也应该是null
        //删除一个节点,长度-1
        size--;
        //继承自抽象类AbstractList,保证快速失败机制的正常执行
        //删除节点是结构性修改
        modCount++;
        return element;
    }

unlinkLast(Node< E > l) 

    //在指定节点l处将链表一分为二
    //链表右边直接丢弃(包含节点l)
    //链表左边是新的链表
    private E unlinkLast(Node<E> l) {
        //获取节点l的元素
        final E element = l.item;
        //获取节点l的上一个节点
        final Node<E> prev = l.prev;
        //清空节点l的元素
        l.item = null;
        //断开节点l与上一个节点的关系
        //在这里将链表一分为二
        //链表右边直接丢弃(包含节点l)
        l.prev = null; 
        //链表左边的尾节点
        //也就是节点l的上一个节点prev
        //成为新链表的尾节点
        //需要对last重新进行初始化
        //保证last永远都是尾节点的引用
        last = prev;
        //---------------下面需要考虑一些其它情况
        //如果prev为null,说明新链表为null
        if (prev == null)
           //那么新链表的首节点也是null
           //需要对first重新初始化
           first = null;
        //如果prev不为null,它就是新链表的尾节点
        //上面的代码只断开了l → prev方向的关系
        //(l.prev = null)
        //LinkedList是双向的
        //所以,还需要断开prev → l方向的关系
        else
           prev.next = null;
           //同时,尾节点的下一个节点也应该是null
        //删除一个节点,长度-1
        size--;
        //继承自抽象类AbstractList,保证快速失败机制的正常执行
        //删除节点是结构性修改
        modCount++;
        return element;
    }

unlink(Node< E > x) 

    //删除指定节点x
    E unlink(Node<E> x) {
        //获取节点x的元素
        final E element = x.item;
        //获取节点x的下一个节点
        final Node<E> next = x.next;
        //获取节点x的上一个节点
        final Node<E> prev = x.prev;
        //如果prev为null,说明x是首节点
        //删除x后,它的下一个节点(next)就自动成为新的首节点
        if (prev == null) {
           //需要对first重新进行初始化,保证first永远都是首节点的引用
           first = next;

        } else {
           prev.next = next;
           x.prev = null;
        }
        //如果next为null,说明x是尾节点
        //删除x后,它的上一个节点(next)就自动成为新的尾节点
        if (next == null) {
           //需要对last重新进行初始化,保证last永远都是尾节点的引用
           last = prev;
        //如果next不为null,只需要维护节点之间的关系
        //删除x,那么它的下一个节点(next.prev)
        //和上一个节点(prev)将直接产生联系
        } else {
           next.prev = prev;
           //linkedList是双向的
           //上面的代码只断开了x → prev方向的关系
           //还需要断开x → next方向的关系
           x.next = null;
        }
        //清空节点x的元素
        x.item = null;
        //删除一个节点,长度-1
        size--;
        //继承自抽象类AbstractList,保证快速失败机制的正常执行
        //删除节点是结构性修改
        modCount++;
        return element;
    }

以上都是LinkedList的内部支撑方法,下面将要介绍LinkedList对外提供的方法,有以下几类:接口Deque的方法、接口Queue的方法、栈的方法等。 

Deque接口方法(双端队列)

Deque的特点是既可以在首部也可以在尾部添加和删除节点。

getFirst()

   //返回首节点的元素
   public E getFirst() {
      //获取首节点
      final Node<E> f = first;
      //如果首节点为null
      if (f == null)
         //抛出NoSuchElementException异常
         throw new NoSuchElementException();
       //返回首节点的元素
       return f.item;
   }

getLast() 

   //返回尾节点的元素
   public E getLast() {
      //获取尾节点
      final Node<E> l = last;
      //如果尾节点为null
      if (l == null)
         //抛出NoSuchElementException异常
         throw new NoSuchElementException();
      //返回尾节点的元素
      return l.item;
   }

removeFirst() 

   //从链表的首部删除节点
   public E removeFirst() {
      //获取首节点
      final Node<E> f = first;
      //如果首节点为null
      if (f == null)
         //抛出NoSuchElementException异常
         throw new NoSuchElementException();
      //参考方法unlinkFirst(Node< E > f)
      return unlinkFirst(f);
      //在方法unlinkFirst(f)中,维护了删除操作发生之后
      //剩下的节点之间的关系(first会被重新初始化)
      //所以f总是新的首节点
   }

removeLast() 

    //从链表的尾部删除节点
    public E removeLast() {
       //获取尾节点
       final Node<E> l = last;
       //如果尾节点为null
       if (l == null)
          //抛出NoSuchElementException异常
          throw new NoSuchElementException();
       //参考方法unlinkLast(Node< E > f)
       return unlinkLast(l);
       //在方法unlinkLast(l)中,维护了删除操作发生之后
       //剩下的节点之间的关系(last会被重新初始化)
       //所以l总是新的尾节点
    }

addFirst(E e) 

    //在链表的首部添加节点
    public void addFirst(E e) {
       //参考方法linkFirst(E e)
       linkFirst(e);
       //在方法linkFirst(e)中,维护了添加操作发生之后
       //添加的节点和原有节点之间的关系
       //实际上,添加的节点就是新的首节点
       //(first会被重新初始化)
    }

addLast(E e) 

    //在链表的尾部添加节点
    public void addLast(E e) {
       //参考方法linkLast(E e)
       linkLast(e);
       //在方法linkLast(e)中,维护了添加操作发生之后
       //添加的节点和原有节点之间的关系
       //实际上,添加的节点就是新的尾节点
       //(last会被重新初始化)
    }

contains(Object o) 

    //判断链表中是否存在包含指定元素o的节点
    public boolean contains(Object o) {
       //如果方法indexOf(o)的返回值为-1,则返回true,否则返回false
       return indexOf(o) != -1;
    }

接口Queue的方法

Queue的特点是只能在尾部添加元素,只能在首部删除元素,归纳起来就是"先进先出".

add(E e)

    //参考方法addLast(E e)
    //在链表的尾部添加元素
    public boolean add(E e) {
       //参考方法linkLast()
       linkLast(e);
       return true;
    }

remove(Object o) 

    //从左至右遍历链表,删除元素与
    //指定元素o相等的第一个节点
    public boolean remove(Object o) {
       //如果o为null
       if (o == null) {
          //通过for循环从左至右遍历链表,x为循环因子
          //x的初始化值为首节点first,只要x不为null
          //就继续将下一个节点赋值给x(步进)
          //第一次循环结束后,x从首节点变成了第二节点
          //以此类推,直到循环到尾节点
          for (Node<E> x = first; x != null; x = x.next) {
             //如果节点元素x.item为null
             if (x.item == null) {
                //删除节点
                unlink(x);
                return true;
             }
          }
       //如果o不为null
       } else {
          //同上
          for (Node<E> x = first; x != null; x = x.next) {
             //如果节点元素x.item与指定元素o相等
             if (o.equals(x.item)) {
                //删除节点
                unlink(x);
                return true;
             }
          }
      }
      //如果链表为空或链表不包含
      //指定元素o,直接终止程序返回false
      return false;
   }

List接口方法

get(int index)

    //返回指定索引为index的节点的元素
    public E get(int index) {
       //检查索引值index是否有效
       //如果无效直接抛出异常
       checkElementIndex(index);
       //参考方法node(int index)
       //返回节点的元素
       return node(index).item;
    }

 set(int index, E element)

    //用指定元素element代替索引值为index的节点的元素
    public E set(int index, E element) {
       //检查索引值index是否有效
       //如果无效直接抛出异常
       checkElementIndex(index);
       //参考方法node(int index)
       //获取索引值为index的节点
       Node<E> x = node(index);
       //获取节点的元素oldVal
       E oldVal = x.item;
       //给节点的元素重新赋值element
       x.item = element;
       //返回元素oldVal
       return oldVal;
    }

add(int index, E element) 

    //将包含指定元素element的节点
    //添加在链表的指定索引位置index
    public void add(int index, E element) {
       //检查索引值index是否有效
       //如果无效直接抛出异常
       checkPositionIndex(index);
       //根据索引值index判断添加节点的位置
       //在链表的尾部添加
       if (index == size)
          //参考方法linkLast(int index)
          linkLast(element);
       //在链表的中间添加
       else
          //参考方法node(int index)
          //参考方法linkBefore(E e, Node< E > succ)
          //先获取索引值为index的节点
          //再将它作为实际参数传入方法
          //linkBefore(E e, Node< E > succ)中
          linkBefore(element, node(index));
    }

remove(int index) 

    //删除指定索引值是index的节点
    public E remove(int index) {
       //检查索引值index是否有效
       //如果无效直接抛出异常
       checkElementIndex(index);
       //参考方法node(int index)
       //参考方法unlink(Node< E > x)
       //先获取索引值为index的节点
       //再将它作为实际参数传入方法
       //unlink(Node< E > x)中
       return unlink(node(index));
    }

node(int index)

    //返回指定索引值为index的非空节点。
    Node<E> node(int index) {
       //这里涉及到一个提高效率的操作
       //因为LinkedList是双向的,既可以
       //从首部开始,也可以从尾部开始
       //所以以链表长度的一半为标准,如果index
       //大于它,则从尾部开始,如果index小于它
       //则从首部开始
       //考虑index小于链表一半的情况
       //size >> 1 等价于size/2
       if (index < (size >> 1)) {
          //获取首节点,从它开始
          //方向是从左至右
          Node<E> x = first;
          //for循环
          for (int i = 0; i < index; i++)
             //步进表达式
             x = x.next;
          //从上面的循环中就能看出链表
          //顺序访问的特点,循环中没有任何
          //的判断或者条件语句,只是单纯的循环
          //从首节点first开始,经过index-2个
          //节点后才到达目标节点 
          //返回目标节点x
          return x;
       //考虑index大于链表一半的情况
       } else {
          //获取尾节点,从它开始
          //方向是从右至左
          Node<E> x = last;
          for (int i = size - 1; i > index; i--)
             //步进表达式
             x = x.prev;
          //返回目标节点x
          return x;
       }
    }

 indexOf(Object o)

    //返回元素与指定元素o相等的
    //第一个节点的索引值
    //从首节点开始遍历链表,方向为从左至右
    public int indexOf(Object o) {
       //链表是顺序访问的
       //第一个节点的索引值为0
       int index = 0;
       //考虑指定元素o为null的情况
       if (o == null) {
          //for循环遍历链表
          //遍历方向为从左至右
          for (Node<E> x = first; x != null; x = x.next) {
             //如果元素为null
             if (x.item == null)
                //返回索引值
                return index;
             //如果元素不为null
             //自动递增索引值
             index++;
           }
       //考虑指定元素o不为null的情况
       } else {
          //for循环遍历链表
          //遍历方向为从左至右
          for (Node<E> x = first; x != null; x = x.next) {
             //如果元素与指定元素o相等
             if (o.equals(x.item))
                //返回索引值
                return index;
             //如果元素与指定元素o不相等
             //自动递增索引值
             index++;
          }
       }
       //如果链表不包含指定元素o,返回-1
       return -1;
    }

lastIndexOf(Object o) 

    //返回元素与指定元素o相等的
    //第一个节点的索引值
    //从尾节点开始遍历链表,方向为从右至左
    public int lastIndexOf(Object o) {
       //链表是顺序访问的
       //第一个节点的索引值为size
       int index = size;
       //考虑指定元素o为null的情况
       if (o == null) {
          //for循环遍历链表
          //遍历方向为从右至左
          for (Node<E> x = last; x != null; x = x.prev) {
             //注意与方法indexOf(Object o)的区别
             //lastIndexOf(Object o)先递减索引值index
             //再进行判断
             index--;
             //如果元素为null
             if (x.item == null)
                //返回索引值index
                return index;
          }
       //考虑指定元素o不为null的情况
       } else {
          //for循环遍历链表
          //遍历方向为从右至左
          for (Node<E> x = last; x != null; x = x.prev) {
             //先递减索引值index
             index--;
             //如果元素与指定元素o相等
             if (o.equals(x.item))
                //返回索引值index
                return index;
          }
       }
       //如果链表不包含指定元素o,返回-1
       return -1;
    }

类Stack的方法 

Queue的特点是只能在尾部添加元素,只能在首部删除元素,归纳起来就是"后进先出"

peek()

    //返回链表首节点的元素
    //如果首节点为null直接返回null
    public E peek() {
       final Node<E> f = first;
       //如果f为null,则返回null,否则返回元素
       return (f == null) ? null : f.item;
    }

element() 

    //返回链表首节点的元素
    //如果首节点为null直接
    //抛出NoSuchElementException异常
    public E element() {
       //参考方法getFirst()
       return getFirst();
    }

poll() 

    //返回链表首节点的元素后删除首节点
    //如果首节点为null直接返回null
    public E poll() {
       final Node<E> f = first;
       //如果f为null,返回null
       //否则返回方法unlinkFirst(f)的结果
       //参考方法unlinkFirst(Node< E > f)
       return (f == null) ? null : unlinkFirst(f);
    }

remove() 

    //在链表的首部删除元素
    //如果首节点为null直接
    //抛出NoSuchElementException异常
    public E remove() {
       //参考方法removeFirst()
       return removeFirst();
    }

offer(E e) 

    //在链表的尾部添加节点
    public boolean offer(E e) {
       //参考方法add(E e)
       return add(e);
    }

offerFirst(E e) 

    //在链表的首部添加节点
    public boolean offerFirst(E e) {
       //参考方法addFirst(E e)
       addFirst(e);
       return true;
    }

offerLast(E e) 

    //在链表的尾部添加节点
    public boolean offerLast(E e) {
       //参考方法addFirst(E e)
       addLast(e);
       return true;
    }

 peekFirst()

    //返回链表首节点的元素
    //如果首节点为null直接返回null
    public E peekFirst() {
        final Node<E> f = first;
        //如果f为null,则返回null,否则返回元素
        return (f == null) ? null : f.item;
    }

peekLast() 

    //返回链表尾节点的元素
    //如果首节点为null直接返回null
    public E peekLast() {
       final Node<E> l = last;
       //如果f为null,则返回null,否则返回元素
       return (l == null) ? null : l.item;
    }

pollFirst() 

    //返回链表首节点的元素后删除首节点
    //如果首节点为null直接返回null
    public E pollFirst() {
       final Node<E> f = first;
       //如果f为null,返回null
       //否则返回方法unlinkFirst(f)的结果
       //参考方法unlinkFirst(Node< E > f)
       return (f == null) ? null : unlinkFirst(f);
    }

pollLast() 

    //返回链表尾节点的元素后删除尾节点
    //如果首节点为null直接返回null
    public E pollLast() {
       final Node<E> l = last;
       //如果f为null,返回null
       //否则返回方法unlinkLast(f)的结果
       //参考方法unlinkLast(Node< E > f)
       return (l == null) ? null : unlinkLast(l);
    }

 push(E e)

    //在链表的首部添加节点
    public void push(E e) {
       //参考方法addFirst(E e)
       addFirst(e);
    }

pop() 

    //在链表的首部删除元素
    //如果首节点为null直接
    //抛出NoSuchElementException异常
    public E pop() {
       //参考方法removeFirst()
       return removeFirst();
    }

listIterator(int index) 

    //返回从指定索引位置index开始的列表迭代器
    public ListIterator<E> listIterator(int index) {
       //检查索引值index是否有效
       //如果无效直接抛出异常
       checkPositionIndex(index);
       //返回一个内部类ListItr对象
       return new ListItr(index);
    }

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值