前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK8的LinkedList源码学习笔记

JDK8的LinkedList源码学习笔记

作者头像
itliusir
发布2018-05-21 16:52:14
4590
发布2018-05-21 16:52:14
举报
文章被收录于专栏:刘君君刘君君

正文:

首先,LinkedList的继承和实现了的类和接口:

LinkedList实现的接口
LinkedList实现的接口

LinkedList实现的接口

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。同时实现了Deque接口,即能将LinkedList当作双端队列使用。

另外实现了Cloneable接口,Serializable接口。 接下来看LinkedList的构造方法:

代码语言:javascript
复制
/**
    * Constructs an empty list.
    */
   public LinkedList() {
   }

   /**
    * Constructs a list containing the elements of the specified
    * collection, in the order they are returned by the collection's
    * iterator.
    *
    * @param  c 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();
       addAll(c);
   }

LinkedList提供了两个构造方法,第一个是默认无参的,第二个是带Collection的类型参数:

  • 使用this()调用默认的构造方法

成员变量分析

代码语言:javascript
复制
/**
    * 当前有多少个节点
    */
transient int size = 0;
   /**
    * 第一个节点.
    * Invariant: (first == null && last == null) ||
    *            (first.prev == null && first.item != null)
    */
   transient Node<E> first;

   /**
    * 最后一个节点.
    * Invariant: (first == null && last == null) ||
    *            (last.next == null && last.item != null)
    */
   transient Node<E> last;

核心方法分析

1. addAll()方法

addAll有两个重载函数,addAll(Collection<? extends E>)型和addAll(int, Collection<? extends E>)型,我们平时习惯调用的addAll(Collection<? extends E>)型会转化为addAll(int, Collection<? extends E>)型,所以我们着重分析此函数即可

代码语言:javascript
复制
public boolean addAll(int index, Collection<? extends E> c) {
	//JDK8将对index的判断封装了一个方法checkPositionIndex(index);
	//这个就不用说了,集合转为数组
       Object[] a = c.toArray();
       int numNew = a.length;
       if (numNew == 0)
           return false;
	//succ指向当前需要插入节点的位置,pred指向其前一个节点
       Node<E> pred, succ;
	//在列表尾部插入的时候
       if (index == size) {
           succ = null;
           pred = last;
       } else {
	//若不是在尾部插入时候则先去根据索引查询对应的元素可见该块最下面的node()方法
           succ = node(index);
           pred = succ.prev;
       }
	//遍历collection中的所有元素将其依次插入到此链表中指定位置
       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;
   }

/**
    * 根据index返回对应元素.
    */
   Node<E> node(int index) {
       // assert isElementIndex(index);
	//若index<size/2正序移位获取索引位置
       if (index < (size >> 1)) {
           Node<E> x = first;
           for (int i = 0; i < index; i++)
               x = x.next;
           return x;
       } else {
           Node<E> x = last;
           for (int i = size - 1; i > index; i--)
               x = x.prev;
           return x;
       }
   }

2. removeXXX()方法

LinkedList提供了头删除removeFirst()、尾删除removeLast()、remove(int index)、remove(Object o)、clear()这些删除元素的方法。

代码语言:javascript
复制
/**
    * Removes and returns the first element from this list.
    */
public E removeFirst() {
       final Node<E> f = first;
       if (f == null)
           throw new NoSuchElementException();
       return unlinkFirst(f);
   }

   /**
    * Removes and returns the last element from this list.
    */
   public E removeLast() {
       final Node<E> l = last;
       if (l == null)
           throw new NoSuchElementException();
       return unlinkLast(l);
   }
/**
    * Unlinks non-null first node f.
    * 删除非空的首节点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
	//将原首节点的next节点设置为首节点
       first = next;
       if (next == null)
           last = null;
       else
           next.prev = null;
       size--;
       modCount++;
       return element;
   }

   /**
    * Unlinks non-null last node l.
    * 删除非空的尾节点f.
    */
   private E unlinkLast(Node<E> l) {
       // assert l == last && l != null;
       final E element = l.item;
       final Node<E> prev = l.prev;
       l.item = null;
       l.prev = null; // help GC
	//将原尾节点的prev节点设置为尾节点
       last = prev;
       if (prev == null)
           first = null;
       else
           prev.next = null;
       size--;
       modCount++;
       return element;
   }


/**
    * Remove.
    */
public boolean remove(Object o) {
       if (o == 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;
   }
/**
    * Unlinks non-null node x.
    * 删除非空节点.
    */
   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;
	//如果被删除节点为头节点
       if (prev == null) {
           first = next;
       } else {
           prev.next = next;
           x.prev = null;
       }
	//如果被删除节点为尾节点
       if (next == null) {
           last = prev;
       } else {
           next.prev = prev;
           x.next = null;
       }

       x.item = null;
       size--; //size-1
       modCount++;
       return element;
   }

/**
    * Removes all of the elements from this list.
    * 清空所有节点.
    */
   public void clear() {
       // Clearing all of the links between nodes is "unnecessary", but:
       // - helps a generational GC if the discarded nodes inhabit
       //   more than one generation
       // - is sure to free memory even if there is a reachable Iterator
       for (Node<E> x = first; x != null; ) {
           Node<E> next = x.next;
           x.item = null;
           x.next = null;
           x.prev = null;
           x = next;
       }
       first = last = null;
       size = 0;
       modCount++;
   }

3. set()方法

代码语言:javascript
复制
//很容易分析,先检查index,然后根据index返回对应元素,最后将元素-->x.item
public E set(int index, E element) {
       checkElementIndex(index);
       Node<E> x = node(index);
       E oldVal = x.item;
       x.item = element;
       return oldVal;
   }

4. getXXX()方法

LinkedList提供了getFirst()、getLast()、contains(Object o)、get(int index)、indexOf(Object o)、lastIndexOf(Object o)这些查找元素的方法。

代码语言:javascript
复制
/**
    * Returns the first element in this list.
    */
   public E getFirst() {
       final Node<E> f = first;
       if (f == null)
           throw new NoSuchElementException();
       return f.item;
   }
/**
    * Returns the last element in this list.
    */
   public E getLast() {
       final Node<E> l = last;
       if (l == null)
           throw new NoSuchElementException();
       return l.item;
   }
public boolean contains(Object o) {
       return indexOf(o) != -1;
   }
/**
    * 正向查找,返回LinkedList中元素值Object o第一次出现的位置,如果元素不存在,则返回-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;
   }
//逆向查找,返回LinkedList中元素值Object o最后一次出现的位置,如果元素不存在,则返回-1
   public int lastIndexOf(Object o) {
       int index = size;
	//LinkedList可以为null
       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;
   }
/**
    * 根据index获取当前元素.
    */
   public E get(int index) {
       checkElementIndex(index);
       return node(index).item;
   }

5. Queue操作

Queue操作提供了peek()、element()、poll()、remove()、offer(E e)这些方法。

代码语言:javascript
复制

//获取但不移除此队列的头;如果此队列为空,则返回 null
   public E peek() {
       final Node<E> f = first;
       return (f == null) ? null : f.item;
   }

   //获取但不移除此队列的头;如果此队列为空,则抛出NoSuchElementException异常
   public E element() {
       return getFirst();
   }

   //获取并移除此队列的头,如果此队列为空,则返回 null
   public E poll() {
       final Node<E> f = first;
       return (f == null) ? null : unlinkFirst(f);
   }

   //获取并移除此队列的头,如果此队列为空,则抛出NoSuchElementException异常
   public E remove() {
       return removeFirst();
   }

   //将指定的元素值(E e)插入此列表末尾
   public boolean offer(E e) {
       return add(e);
   }

6. Deque操作

Deque操作提供了offerFirst(E e)、offerLast(E e)、peekFirst()、peekLast()、pollFirst()、pollLast()、push(E e)、pop()、removeFirstOccurrence(Object o)、removeLastOccurrence(Object o)这些方法。

代码语言:javascript
复制

//将指定的元素值(E e)插入此列表末尾
   public boolean offer(E e) {
       return add(e);
   }

   // Deque operations

   //将指定的元素插入此双端队列的开头
   public boolean offerFirst(E e) {
       addFirst(e);
       return true;
   }

   //将指定的元素插入此双端队列的末尾
   public boolean offerLast(E e) {
       addLast(e);
       return true;
   }

   //获取,但不移除此双端队列的第一个元素;如果此双端队列为空,则返回 null
   public E peekFirst() {
       final Node<E> f = first;
       return (f == null) ? null : f.item;
    }

   //获取,但不移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null
   public E peekLast() {
       final Node<E> l = last;
       return (l == null) ? null : l.item;
   }

   //获取并移除此双端队列的第一个元素;如果此双端队列为空,则返回 null
   public E pollFirst() {
       final Node<E> f = first;
       return (f == null) ? null : unlinkFirst(f);
   }

   //获取并移除此双端队列的最后一个元素;如果此双端队列为空,则返回 null
   public E pollLast() {
       final Node<E> l = last;
       return (l == null) ? null : unlinkLast(l);
   }

   //将一个元素推入此双端队列所表示的堆栈(换句话说,此双端队列的头部)
   public void push(E e) {
       addFirst(e);
   }

   //从此双端队列所表示的堆栈中弹出一个元素(换句话说,移除并返回此双端队列的头部)
   public E pop() {
       return removeFirst();
   }

   //从此双端队列移除第一次出现的指定元素,如果列表中不包含次元素,则没有任何改变
   public boolean removeFirstOccurrence(Object o) {
       return remove(o);
   }

   //从此双端队列移除最后一次出现的指定元素,如果列表中不包含次元素,则没有任何改变
   public boolean removeLastOccurrence(Object o) {
       //由于LinkedList中允许存放null,因此下面通过两种情况来分别处理
       if (o == null) {
           for (Node<E> x = last; x != null; x = x.prev) { //逆向向前
               if (x.item == null) {
                   unlink(x);
                   return true;
               }
           }
       } else {
           for (Node<E> x = last; x != null; x = x.prev) {
               if (o.equals(x.item)) {
                   unlink(x);
                   return true;
               }
           }
       }
       return false;
   }

LinkedList同样也采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

晚安~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 正文:
  • 晚安~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档