java1.7集合源码阅读:LinkedList

Posted jessezeng

tags:

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

先看看类定义:

1 public class LinkedList<E>
2     extends AbstractSequentialList<E>
3     implements List<E>, Deque<E>, Cloneable, java.io.Serializable
4 {
5   .......  
6 }
LinkedList与ArrayList相比,LinkedList不再实现RandomAccess接口,表明不支持快速随机访问数据,但实现了Deque接口,可当队列使用,Deque继承自Queue,接口定义:
 1 public interface Queue<E> extends Collection<E> {
 2         void addFirst(E e);
 3         void addLast(E e);
 4         boolean offerFirst(E e);
 5         boolean offerLast(E e);
 6         E removeFirst();
 7         E removeLast();
 8         E pollFirst();
 9         E pollLast();
10         E getFirst();
11         E getLast();
12         E peekFirst();
13         E peekLast();
14         boolean removeFirstOccurrence(Object o);
15         boolean removeLastOccurrence(Object o);
16         boolean add(E e);
17         boolean offer(E e);        
18         E remove();
19         E poll();
20         E element();
21         E peek();
22         void push(E e);
23         boolean remove(Object o);
24         boolean contains(Object o);    
25         public int size();
26         Iterator<E> iterator();    
27         Iterator<E> descendingIterator();
28 }

看看LinkedList的两个属性,一个头节点,一个末节点:
 1     /**
 2      * Pointer to first node.
 3      * Invariant: (first == null && last == null) ||
 4      *            (first.prev == null && first.item != null)
 5      */
 6     transient Node<E> first;
 7 
 8     /**
 9      * Pointer to last node.
10      * Invariant: (first == null && last == null) ||
11      *            (last.next == null && last.item != null)
12      */
13     transient Node<E> last;

在看看Node的定义:

 1     private static class Node<E> {
 2         E item;
 3         Node<E> next;
 4         Node<E> prev;
 5 
 6         Node(Node<E> prev, E element, Node<E> next) {
 7             this.item = element;
 8             this.next = next;
 9             this.prev = prev;
10         }
11     }

Node中保存着存入集合的对象,同时也保存着上一个节点和下一个节点,由此可知,LinkedList 内部采用的是双向链表结构。

再看看CRUD操作:

add:

 1     /**
 2      * Appends the specified element to the end of this list.
 3      *
 4      * <p>This method is equivalent to {@link #addLast}.
 5      *
 6      * @param e element to be appended to this list
 7      * @return {@code true} (as specified by {@link Collection#add})
 8      */
 9     public boolean add(E e) {
10         linkLast(e);     //last节点后拼接一个节点
11         return true;
12     }
13     /**
14      * Links e as last element.
15      */
16     void linkLast(E e) {
17         final Node<E> l = last;
18         final Node<E> newNode = new Node<>(l, e, null);
19         last = newNode;  // 将last节点指向当前新创建的节点,新节点变为last节点,原last节点的下一个节点指向最新的last节点
20    if (l == null)
21     first = newNode;
22   else
23     l.next = newNode;
24   size++;
25   modCount++;
26 }

 与linkLast对应的还有linkFirst:

 1     /**
 2      * Links e as first element.
 3      */将元素添加到首节点
 4     private void linkFirst(E e) {
 5         final Node<E> f = first;
 6         final Node<E> newNode = new Node<>(null, e, f);
 7         first = newNode;
 8         if (f == null)
 9             last = newNode;
10         else
11             f.prev = newNode;
12         size++;
13         modCount++;
14     }

既然存在在对尾、队尾添加元素,那么是不是也应该存在在指定某个元素之前或之后添加元素呢,是的,的确存在:

 1     /**
 2      * Inserts element e before non-null Node succ.
 3      */
 4     void linkBefore(E e, Node<E> succ) {
 5         // assert succ != null;
 6         final Node<E> pred = succ.prev;
 7         final Node<E> newNode = new Node<>(pred, e, succ);
 8         succ.prev = newNode;
 9         if (pred == null)
10             first = newNode;
11         else
12             pred.next = newNode;
13         size++;
14         modCount++;
15     }

与此同时也还存在另外两个方法,一个是在指定节点位置添加元素,另一个是将指定位置的元素修改成当前元素:

 1    /**
 2      * Replaces the element at the specified position in this list with the
 3      * specified element.
 4      *
 5      * @param index index of the element to replace
 6      * @param element element to be stored at the specified position
 7      * @return the element previously at the specified position
 8      * @throws IndexOutOfBoundsException {@inheritDoc}
 9      */
10     public E set(int index, E element) {  //指定位置的元素修改成当前元素
11         checkElementIndex(index);
12         Node<E> x = node(index);
13         E oldVal = x.item;
14         x.item = element;
15         return oldVal;
16     }
17 
18     /**
19      * Inserts the specified element at the specified position in this list.
20      * Shifts the element currently at that position (if any) and any
21      * subsequent elements to the right (adds one to their indices).
22      *
23      * @param index index at which the specified element is to be inserted
24      * @param element element to be inserted
25      * @throws IndexOutOfBoundsException {@inheritDoc}
26      */
27     public void add(int index, E element) {  //指定节点位置添加元素
28         checkPositionIndex(index);
29 
30         if (index == size)
31             linkLast(element);
32         else
33             linkBefore(element, node(index));
34     }

linkedList  虽然提供了get(index) 方法,但并不没有ArrayList那样高效的获取,而是变量整个数据结构,此时,做了一个优化,根据index判断元素是在链表的前端还是后端,如果是后端,则从队尾开始遍历:

 1     /**
 2      * Returns the element at the specified position in this list.
 3      *
 4      * @param index index of the element to return
 5      * @return the element at the specified position in this list
 6      * @throws IndexOutOfBoundsException {@inheritDoc}
 7      */
 8     public E get(int index) {
 9         checkElementIndex(index);
10         return node(index).item;
11     }
12     /**
13      * Returns the (non-null) Node at the specified element index.
14      */
15     Node<E> node(int index) {
16         // assert isElementIndex(index);
17 
18         if (index < (size >> 1)) {
19             Node<E> x = first;
20             for (int i = 0; i < index; i++)
21                 x = x.next;
22             return x;
23         } else {
24             Node<E> x = last;
25             for (int i = size - 1; i > index; i--)
26                 x = x.prev;
27             return x;
28         }
29     }

获取对首或队尾元素就简单了,直接返回对首或队尾元素就ok了:

 1   /**
 2      * Returns the first element in this list.
 3      *
 4      * @return the first element in this list
 5      * @throws NoSuchElementException if this list is empty
 6      */
 7     public E getFirst() {
 8         final Node<E> f = first;
 9         if (f == null)
10             throw new NoSuchElementException();
11         return f.item;
12     }
13 
14     /**
15      * Returns the last element in this list.
16      *
17      * @return the last element in this list
18      * @throws NoSuchElementException if this list is empty
19      */
20     public E getLast() {
21         final Node<E> l = last;
22         if (l == null)
23             throw new NoSuchElementException();
24         return l.item;
25     }

LinkedList 无参remove方法,是直接删除队首元素:

 1   /**
 2      * Retrieves and removes the head (first element) of this list.
 3      *
 4      * @return the head of this list
 5      * @throws NoSuchElementException if this list is empty
 6      * @since 1.5
 7      */
 8     public E remove() {
 9         return removeFirst();
10     }
11     /**
12      * Removes and returns the first element from this list.
13      *
14      * @return the first element from this list
15      * @throws NoSuchElementException if this list is empty
16      */
17     public E removeFirst() {
18         final Node<E> f = first;
19         if (f == null)
20             throw new NoSuchElementException();
21         return unlinkFirst(f);
22     }
23     /**
24      * Unlinks non-null first node f.
25      */
26     private E unlinkFirst(Node<E> f) {  //将对首元素设置null,将对首的下一元素作为对首元素
27         // assert f == first && f != null;
28         final E element = f.item;
29         final Node<E> next = f.next;
30         f.item = null;
31         f.next = null; // help GC
32         first = next;
33         if (next == null)
34             last = null;
35         else
36             next.prev = null;
37         size--;
38         modCount++;
39         return element;
40     }

remove(Object),变量整个数据结构删除:

 1   /**
 2      * Removes the first occurrence of the specified element from this list,
 3      * if it is present.  If this list does not contain the element, it is
 4      * unchanged.  More formally, removes the element with the lowest index
 5      * {@code i} such that
 6      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
 7      * (if such an element exists).  Returns {@code true} if this list
 8      * contained the specified element (or equivalently, if this list
 9      * changed as a result of the call).
10      *
11      * @param o element to be removed from this list, if present
12      * @return {@code true} if this list contained the specified element
13      */
14     public boolean remove(Object o) {
15         if (o == null) {//先判断是否是空值
16             for (Node<E> x = first; x != null; x = x.next) {
17                 if (x.item == null) {
18                     unlink(x);
19                     return true;
20                 }
21             }
22         } else {
23             for (Node<E> x = first; x != null; x = x.next) {
24                 if (o.equals(x.item)) {
25                     unlink(x);
26                     return true;
27                 }
28             }
29         }
30         return false;
31     }

linkedList实现了队列接口,使用中也可以直接当队列用:

 1    /**
 2      * Adds the specified element as the tail (last element) of this list.
 3      *
 4      * @param e the element to add
 5      * @return {@code true} (as specified by {@link Queue#offer})
 6      * @since 1.5
 7      */
 8     public boolean offer(E e) {
 9         return add(e);
10     }
11 
12     // Deque operations
13     /**
14      * Inserts the specified element at the front of this list.
15      *
16      * @param e the element to insert
17      * @return {@code true} (as specified by {@link Deque#offerFirst})
18      * @since 1.6
19      */
20     public boolean offerFirst(E e) {
21         addFirst(e);
22         return true;
23     }
24 
25     /**
26      * Inserts the specified element at the end of this list.
27      *
28      * @param e the element to insert
29      * @return {@code true} (as specified by {@link Deque#offerLast})
30      * @since 1.6
31      */
32     public boolean offerLast(E e) {
33         addLast(e);
34         return true;
35     }

linkedList 还提供了几个方法,可以直接通过peek方法获取元素,需要注意的是获取之后并不会从队列中删除该元素:

 1    /**
 2      * Retrieves, but does not remove, the first element of this list,
 3      * or returns {@code null} if this list is empty.
 4      *
 5      * @return the first element of this list, or {@code null}
 6      *         if this list is empty
 7      * @since 1.6
 8      */
 9     public E peekFirst() {
10         final Node<E> f = first;
11         return (f == null) ? null : f.item;
12      }
13 
14     /**
15      * Retrieves, but does not remove, the last element of this list,
16      * or returns {@code null} if this list is empty.
17      *
18      * @return the last element of this list, or {@code null}
19      *         if this list is empty
20      * @since 1.6
21      */
22     public E peekLast() {
23         final Node<E> l = last;
24         return (l == null) ? null : l.item;
25     }

与peek对应的还有poll方法,同样是获取元素,不同点在于,获取元素之后,该元素将会从队列中删除。

 1   /**
 2      * Retrieves and removes the first element of this list,
 3      * or returns {@code null} if this list is empty.
 4      *
 5      * @return the first element of this list, or {@code null} if
 6      *     this list is empty
 7      * @since 1.6
 8      */
 9     public E pollFirst() {
10         final Node<E> f = first;
11         return (f == null) ? null : unlinkFirst(f);
12     }
13 
14     /**
15      * Retrieves and removes the last element of this list,
16      * or returns {@code null} if this list is empty.
17      *
18      * @return the last element of this list, or {@code null} if
19      *     this list is empty
20      * @since 1.6
21      */
22     public E pollLast() {
23         final Node<E> l = last;
24         return (l == null) ? null : unlinkLast(l);
25     }

LinkedList提供了多种操作数据集合的方法,但最重要的一点就是,整个是实现是非线程安全的,在多线程下需要进行同步处理,或者使用并发包中的对应实现类。

 

 

 



以上是关于java1.7集合源码阅读:LinkedList的主要内容,如果未能解决你的问题,请参考以下文章

java1.7集合源码阅读: Stack

jdk源码阅读笔记之java集合框架(LinkedList)

JDK1.8JDK1.8集合源码阅读——LinkedList

JAVA 集合类(java.util)源码阅读笔记------LinkedList

javase基础回顾LinkedList需要注意的知识点 阅读源码收获

Java 集合学习笔记:LinkedList