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



  • 相关阅读:
    Windows下搭建JSP开发环境
    ssh 学习笔记
    18 11 27 长连接 短链接
    18 11 26 用多进程 多线程 携程 实现 http 服务器的创建
    18 11 24 简单的http服务器
    关于 某个智慧树课堂的 机器与机器交流方法
    18 11 23 正则学习
    尝试解决 : Microsoft Visual C++ 14.0 is required 的问题
    18 11 20 网络通信 ----多任务---- 携程 ----生成器
    18 11 20 网络通信 ----多任务---- 携程 ----迭代器
  • 原文地址:https://www.cnblogs.com/jessezeng/p/5043887.html
Copyright © 2020-2023  润新知