• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
乐碎碎
程序媛想的事儿
博客园    首页    新随笔    联系   管理    订阅  订阅
Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

java 集合系列目录:

Java 集合系列 01 总体框架

Java 集合系列 02 Collection架构

Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 

Java 集合系列 05 Vector详细介绍(源码解析)和使用示例

Java 集合系列 06 Stack详细介绍(源码解析)和使用示例

Java 集合系列 07 List总结(LinkedList, ArrayList等使用场景和性能分析)

Java 集合系列 08 Map架构

Java 集合系列 09 HashMap详细介绍(源码解析)和使用示例

Java 集合系列 10 Hashtable详细介绍(源码解析)和使用示例

Java 集合系列 11 hashmap 和 hashtable 的区别

Java 集合系列 12 TreeMap

Java 集合系列 13 WeakHashMap

Java 集合系列 14 hashCode

Java 集合系列 15 Map总结

Java 集合系列 16 HashSet

Java 集合系列 17 TreeSet

 

概要 

和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码;最后再通过实例来学会使用LinkedList。内容包括:
第1部分 LinkedList介绍
第2部分 LinkedList数据结构
第3部分 LinkedList源码解析(基于JDK1.7)
第4部分 LinkedList遍历方式

第1部分 LinkedList介绍

LinkedList简介

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。

 

LinkedList构造函数

// 默认构造函数
LinkedList()

// 创建一个LinkedList,保护Collection中的全部元素。
LinkedList(Collection<? extends E> collection)

 

LinkedList的API 

LinkedList的API
boolean       add(E object)
void          add(int location, E object)
boolean       addAll(Collection<? extends E> collection)
boolean       addAll(int location, Collection<? extends E> collection)
void          addFirst(E object)
void          addLast(E object)
void          clear()
Object        clone()
boolean       contains(Object object)
Iterator<E>   descendingIterator()
E             element()
E             get(int location)
E             getFirst()
E             getLast()
int           indexOf(Object object)
int           lastIndexOf(Object object)
ListIterator<E>     listIterator(int location)
boolean       offer(E o)
boolean       offerFirst(E e)
boolean       offerLast(E e)
E             peek()
E             peekFirst()
E             peekLast()
E             poll()
E             pollFirst()
E             pollLast()
E             pop()
void          push(E e)
E             remove()
E             remove(int location)
boolean       remove(Object object)
E             removeFirst()
boolean       removeFirstOccurrence(Object o)
E             removeLast()
boolean       removeLastOccurrence(Object o)
E             set(int location, E object)
int           size()
<T> T[]       toArray(T[] contents)
Object[]     toArray()

AbstractSequentialList简介

在介绍LinkedList的源码之前,先介绍一下AbstractSequentialList。毕竟,LinkedList是AbstractSequentialList的子类。

AbstractSequentialList 实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些函数。这些接口都是随机访问List的,LinkedList是双向链表;既然它继承于AbstractSequentialList,就相当于已经实现了“get(int index)这些接口”。

此外,我们若需要通过AbstractSequentialList自己实现一个列表,只需要扩展此类,并提供 listIterator() 和 size() 方法的实现即可。若要实现不可修改的列表,则需要实现列表迭代器的 hasNext、next、hasPrevious、previous 和 index 方法即可。

第2部分 LinkedList数据结构

LinkedList的继承关系

java.lang.Object
   ↳     java.util.AbstractCollection<E>
         ↳     java.util.AbstractList<E>
               ↳     java.util.AbstractSequentialList<E>
                     ↳     java.util.LinkedList<E>

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}

LinkedList与Collection关系如下图:

 

第3部分 LinkedList源码解析(基于JDK1.7)

为了更了解LinkedList的原理,下面对LinkedList源码代码作出分析。

在阅读源码之前,我们先对LinkedList的整体实现进行大致说明:
    LinkedList实际上是通过双向链表去实现的。既然是双向链表,那么它的顺序访问会非常高效,而随机访问效率比较低。
    既然LinkedList是通过双向链表的,但是它也实现了List接口{也就是说,它实现了get(int location)、remove(int location)等“根据索引值来获取、删除节点的函数”}。LinkedList是如何实现List的这些接口的,如何将“双向链表和索引值联系起来的”?
    实际原理非常简单,它就是通过一个计数索引值来实现的。例如,当我们调用get(int location)时,首先会比较“location”和“双向链表长度的1/2”;若前者大,则从链表头开始往后查找,直到location位置;否则,从链表末尾开始先前查找,直到location位置。
   这就是“双线链表和索引值联系起来”的方法。

好了,接下来开始阅读源码(只要理解双向链表,那么LinkedList的源码很容易理解的)。

有关LinkedList在JDK1.6和JDK1.7的区别以及优化,参看 JDK1.7-LinkedList循环链表优化,这里列出是1.7的源码

其中 Node:

private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

 

   1 public class LinkedList<E>
   2     extends AbstractSequentialList<E>
   3     implements List<E>, Deque<E>, Cloneable, java.io.Serializable
   4 {
   5     transient int size = 0;
   6 
   7     /**
   8      * Pointer to first node.
   9      * Invariant: (first == null && last == null) ||
  10      *            (first.prev == null && first.item != null)
  11      */
  12     transient Node<E> first;
  13 
  14     /**
  15      * Pointer to last node.
  16      * Invariant: (first == null && last == null) ||
  17      *            (last.next == null && last.item != null)
  18      */
  19     transient Node<E> last;
  20 
  21     /**
  22      * Constructs an empty list.
  23      */
  24     public LinkedList() {
  25     }
  26 
  27     /**
  28      * Constructs a list containing the elements of the specified
  29      * collection, in the order they are returned by the collection's
  30      * iterator.
  31      *
  32      * @param  c the collection whose elements are to be placed into this list
  33      * @throws NullPointerException if the specified collection is null
  34      */
  35     public LinkedList(Collection<? extends E> c) {
  36         this();
  37         addAll(c);
  38     }
  39 
  40     /**
  41      * Links e as first element.
  42      */
  43     private void linkFirst(E e) {
  44         final Node<E> f = first;
  45         final Node<E> newNode = new Node<>(null, e, f);
  46         first = newNode;
  47         if (f == null)
  48             last = newNode;
  49         else
  50             f.prev = newNode;
  51         size++;
  52         modCount++;
  53     }
  54 
  55     /**
  56      * Links e as last element.
  57      */
  58     void linkLast(E e) {
  59         final Node<E> l = last;
  60         final Node<E> newNode = new Node<>(l, e, null);
  61         last = newNode;
  62         if (l == null)
  63             first = newNode;
  64         else
  65             l.next = newNode;
  66         size++;
  67         modCount++;
  68     }
  69 
  70     /**
  71      * Inserts element e before non-null Node succ.
  72      */
  73     void linkBefore(E e, Node<E> succ) {
  74         // assert succ != null;
  75         final Node<E> pred = succ.prev;
  76         final Node<E> newNode = new Node<>(pred, e, succ);
  77         succ.prev = newNode;
  78         if (pred == null)
  79             first = newNode;
  80         else
  81             pred.next = newNode;
  82         size++;
  83         modCount++;
  84     }
  85 
  86     /**
  87      * Unlinks non-null first node f.
  88      */
  89     private E unlinkFirst(Node<E> f) {
  90         // assert f == first && f != null;
  91         final E element = f.item;
  92         final Node<E> next = f.next;
  93         f.item = null;
  94         f.next = null; // help GC
  95         first = next;
  96         if (next == null)
  97             last = null;
  98         else
  99             next.prev = null;
 100         size--;
 101         modCount++;
 102         return element;
 103     }
 104 
 105     /**
 106      * Unlinks non-null last node l.
 107      */
 108     private E unlinkLast(Node<E> l) {
 109         // assert l == last && l != null;
 110         final E element = l.item;
 111         final Node<E> prev = l.prev;
 112         l.item = null;
 113         l.prev = null; // help GC
 114         last = prev;
 115         if (prev == null)
 116             first = null;
 117         else
 118             prev.next = null;
 119         size--;
 120         modCount++;
 121         return element;
 122     }
 123 
 124     /**
 125      * Unlinks non-null node x.
 126      */
 127     E unlink(Node<E> x) {
 128         // assert x != null;
 129         final E element = x.item;
 130         final Node<E> next = x.next;
 131         final Node<E> prev = x.prev;
 132 
 133         if (prev == null) {
 134             first = next;
 135         } else {
 136             prev.next = next;
 137             x.prev = null;
 138         }
 139 
 140         if (next == null) {
 141             last = prev;
 142         } else {
 143             next.prev = prev;
 144             x.next = null;
 145         }
 146 
 147         x.item = null;
 148         size--;
 149         modCount++;
 150         return element;
 151     }
 152 
 153     /**
 154      * Returns the first element in this list.
 155      *
 156      * @return the first element in this list
 157      * @throws NoSuchElementException if this list is empty
 158      */
 159     public E getFirst() {
 160         final Node<E> f = first;
 161         if (f == null)
 162             throw new NoSuchElementException();
 163         return f.item;
 164     }
 165 
 166     /**
 167      * Returns the last element in this list.
 168      *
 169      * @return the last element in this list
 170      * @throws NoSuchElementException if this list is empty
 171      */
 172     public E getLast() {
 173         final Node<E> l = last;
 174         if (l == null)
 175             throw new NoSuchElementException();
 176         return l.item;
 177     }
 178 
 179     /**
 180      * Removes and returns the first element from this list.
 181      *
 182      * @return the first element from this list
 183      * @throws NoSuchElementException if this list is empty
 184      */
 185     public E removeFirst() {
 186         final Node<E> f = first;
 187         if (f == null)
 188             throw new NoSuchElementException();
 189         return unlinkFirst(f);
 190     }
 191 
 192     /**
 193      * Removes and returns the last element from this list.
 194      *
 195      * @return the last element from this list
 196      * @throws NoSuchElementException if this list is empty
 197      */
 198     public E removeLast() {
 199         final Node<E> l = last;
 200         if (l == null)
 201             throw new NoSuchElementException();
 202         return unlinkLast(l);
 203     }
 204 
 205     /**
 206      * Inserts the specified element at the beginning of this list.
 207      *
 208      * @param e the element to add
 209      */
 210     public void addFirst(E e) {
 211         linkFirst(e);
 212     }
 213 
 214     /**
 215      * Appends the specified element to the end of this list.
 216      *
 217      * <p>This method is equivalent to {@link #add}.
 218      *
 219      * @param e the element to add
 220      */
 221     public void addLast(E e) {
 222         linkLast(e);
 223     }
 224 
 225     /**
 226      * Returns {@code true} if this list contains the specified element.
 227      * More formally, returns {@code true} if and only if this list contains
 228      * at least one element {@code e} such that
 229      * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
 230      *
 231      * @param o element whose presence in this list is to be tested
 232      * @return {@code true} if this list contains the specified element
 233      */
 234     public boolean contains(Object o) {
 235         return indexOf(o) != -1;
 236     }
 237 
 238     /**
 239      * Returns the number of elements in this list.
 240      *
 241      * @return the number of elements in this list
 242      */
 243     public int size() {
 244         return size;
 245     }
 246 
 247     /**
 248      * Appends the specified element to the end of this list.
 249      *
 250      * <p>This method is equivalent to {@link #addLast}.
 251      *
 252      * @param e element to be appended to this list
 253      * @return {@code true} (as specified by {@link Collection#add})
 254      */
 255     public boolean add(E e) {
 256         linkLast(e);
 257         return true;
 258     }
 259 
 260     /**
 261      * Removes the first occurrence of the specified element from this list,
 262      * if it is present.  If this list does not contain the element, it is
 263      * unchanged.  More formally, removes the element with the lowest index
 264      * {@code i} such that
 265      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
 266      * (if such an element exists).  Returns {@code true} if this list
 267      * contained the specified element (or equivalently, if this list
 268      * changed as a result of the call).
 269      *
 270      * @param o element to be removed from this list, if present
 271      * @return {@code true} if this list contained the specified element
 272      */
 273     public boolean remove(Object o) {
 274         if (o == null) {
 275             for (Node<E> x = first; x != null; x = x.next) {
 276                 if (x.item == null) {
 277                     unlink(x);
 278                     return true;
 279                 }
 280             }
 281         } else {
 282             for (Node<E> x = first; x != null; x = x.next) {
 283                 if (o.equals(x.item)) {
 284                     unlink(x);
 285                     return true;
 286                 }
 287             }
 288         }
 289         return false;
 290     }
 291 
 292     /**
 293      * Appends all of the elements in the specified collection to the end of
 294      * this list, in the order that they are returned by the specified
 295      * collection's iterator.  The behavior of this operation is undefined if
 296      * the specified collection is modified while the operation is in
 297      * progress.  (Note that this will occur if the specified collection is
 298      * this list, and it's nonempty.)
 299      *
 300      * @param c collection containing elements to be added to this list
 301      * @return {@code true} if this list changed as a result of the call
 302      * @throws NullPointerException if the specified collection is null
 303      */
 304     public boolean addAll(Collection<? extends E> c) {
 305         return addAll(size, c);
 306     }
 307 
 308     /**
 309      * Inserts all of the elements in the specified collection into this
 310      * list, starting at the specified position.  Shifts the element
 311      * currently at that position (if any) and any subsequent elements to
 312      * the right (increases their indices).  The new elements will appear
 313      * in the list in the order that they are returned by the
 314      * specified collection's iterator.
 315      *
 316      * @param index index at which to insert the first element
 317      *              from the specified collection
 318      * @param c collection containing elements to be added to this list
 319      * @return {@code true} if this list changed as a result of the call
 320      * @throws IndexOutOfBoundsException {@inheritDoc}
 321      * @throws NullPointerException if the specified collection is null
 322      */
 323     public boolean addAll(int index, Collection<? extends E> c) {
 324         checkPositionIndex(index);
 325 
 326         Object[] a = c.toArray();
 327         int numNew = a.length;
 328         if (numNew == 0)
 329             return false;
 330 
 331         Node<E> pred, succ;
 332         if (index == size) {
 333             succ = null;
 334             pred = last;
 335         } else {
 336             succ = node(index);
 337             pred = succ.prev;
 338         }
 339 
 340         for (Object o : a) {
 341             @SuppressWarnings("unchecked") E e = (E) o;
 342             Node<E> newNode = new Node<>(pred, e, null);
 343             if (pred == null)
 344                 first = newNode;
 345             else
 346                 pred.next = newNode;
 347             pred = newNode;
 348         }
 349 
 350         if (succ == null) {
 351             last = pred;
 352         } else {
 353             pred.next = succ;
 354             succ.prev = pred;
 355         }
 356 
 357         size += numNew;
 358         modCount++;
 359         return true;
 360     }
 361 
 362     /**
 363      * Removes all of the elements from this list.
 364      * The list will be empty after this call returns.
 365      */
 366     public void clear() {
 367         // Clearing all of the links between nodes is "unnecessary", but:
 368         // - helps a generational GC if the discarded nodes inhabit
 369         //   more than one generation
 370         // - is sure to free memory even if there is a reachable Iterator
 371         for (Node<E> x = first; x != null; ) {
 372             Node<E> next = x.next;
 373             x.item = null;
 374             x.next = null;
 375             x.prev = null;
 376             x = next;
 377         }
 378         first = last = null;
 379         size = 0;
 380         modCount++;
 381     }
 382 
 383 
 384     // Positional Access Operations
 385 
 386     /**
 387      * Returns the element at the specified position in this list.
 388      *
 389      * @param index index of the element to return
 390      * @return the element at the specified position in this list
 391      * @throws IndexOutOfBoundsException {@inheritDoc}
 392      */
 393     public E get(int index) {
 394         checkElementIndex(index);
 395         return node(index).item;
 396     }
 397 
 398     /**
 399      * Replaces the element at the specified position in this list with the
 400      * specified element.
 401      *
 402      * @param index index of the element to replace
 403      * @param element element to be stored at the specified position
 404      * @return the element previously at the specified position
 405      * @throws IndexOutOfBoundsException {@inheritDoc}
 406      */
 407     public E set(int index, E element) {
 408         checkElementIndex(index);
 409         Node<E> x = node(index);
 410         E oldVal = x.item;
 411         x.item = element;
 412         return oldVal;
 413     }
 414 
 415     /**
 416      * Inserts the specified element at the specified position in this list.
 417      * Shifts the element currently at that position (if any) and any
 418      * subsequent elements to the right (adds one to their indices).
 419      *
 420      * @param index index at which the specified element is to be inserted
 421      * @param element element to be inserted
 422      * @throws IndexOutOfBoundsException {@inheritDoc}
 423      */
 424     public void add(int index, E element) {
 425         checkPositionIndex(index);
 426 
 427         if (index == size)
 428             linkLast(element);
 429         else
 430             linkBefore(element, node(index));
 431     }
 432 
 433     /**
 434      * Removes the element at the specified position in this list.  Shifts any
 435      * subsequent elements to the left (subtracts one from their indices).
 436      * Returns the element that was removed from the list.
 437      *
 438      * @param index the index of the element to be removed
 439      * @return the element previously at the specified position
 440      * @throws IndexOutOfBoundsException {@inheritDoc}
 441      */
 442     public E remove(int index) {
 443         checkElementIndex(index);
 444         return unlink(node(index));
 445     }
 446 
 447     /**
 448      * Tells if the argument is the index of an existing element.
 449      */
 450     private boolean isElementIndex(int index) {
 451         return index >= 0 && index < size;
 452     }
 453 
 454     /**
 455      * Tells if the argument is the index of a valid position for an
 456      * iterator or an add operation.
 457      */
 458     private boolean isPositionIndex(int index) {
 459         return index >= 0 && index <= size;
 460     }
 461 
 462     /**
 463      * Constructs an IndexOutOfBoundsException detail message.
 464      * Of the many possible refactorings of the error handling code,
 465      * this "outlining" performs best with both server and client VMs.
 466      */
 467     private String outOfBoundsMsg(int index) {
 468         return "Index: "+index+", Size: "+size;
 469     }
 470 
 471     private void checkElementIndex(int index) {
 472         if (!isElementIndex(index))
 473             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
 474     }
 475 
 476     private void checkPositionIndex(int index) {
 477         if (!isPositionIndex(index))
 478             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
 479     }
 480 
 481     /**
 482      * Returns the (non-null) Node at the specified element index.
 483      */
 484     Node<E> node(int index) {
 485         // assert isElementIndex(index);
 486 
 487         if (index < (size >> 1)) {
 488             Node<E> x = first;
 489             for (int i = 0; i < index; i++)
 490                 x = x.next;
 491             return x;
 492         } else {
 493             Node<E> x = last;
 494             for (int i = size - 1; i > index; i--)
 495                 x = x.prev;
 496             return x;
 497         }
 498     }
 499 
 500     // Search Operations
 501 
 502     /**
 503      * Returns the index of the first occurrence of the specified element
 504      * in this list, or -1 if this list does not contain the element.
 505      * More formally, returns the lowest index {@code i} such that
 506      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
 507      * or -1 if there is no such index.
 508      *
 509      * @param o element to search for
 510      * @return the index of the first occurrence of the specified element in
 511      *         this list, or -1 if this list does not contain the element
 512      */
 513     public int indexOf(Object o) {
 514         int index = 0;
 515         if (o == null) {
 516             for (Node<E> x = first; x != null; x = x.next) {
 517                 if (x.item == null)
 518                     return index;
 519                 index++;
 520             }
 521         } else {
 522             for (Node<E> x = first; x != null; x = x.next) {
 523                 if (o.equals(x.item))
 524                     return index;
 525                 index++;
 526             }
 527         }
 528         return -1;
 529     }
 530 
 531     /**
 532      * Returns the index of the last occurrence of the specified element
 533      * in this list, or -1 if this list does not contain the element.
 534      * More formally, returns the highest index {@code i} such that
 535      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
 536      * or -1 if there is no such index.
 537      *
 538      * @param o element to search for
 539      * @return the index of the last occurrence of the specified element in
 540      *         this list, or -1 if this list does not contain the element
 541      */
 542     public int lastIndexOf(Object o) {
 543         int index = size;
 544         if (o == null) {
 545             for (Node<E> x = last; x != null; x = x.prev) {
 546                 index--;
 547                 if (x.item == null)
 548                     return index;
 549             }
 550         } else {
 551             for (Node<E> x = last; x != null; x = x.prev) {
 552                 index--;
 553                 if (o.equals(x.item))
 554                     return index;
 555             }
 556         }
 557         return -1;
 558     }
 559 
 560     // Queue operations.
 561 
 562     /**
 563      * Retrieves, but does not remove, the head (first element) of this list.
 564      *
 565      * @return the head of this list, or {@code null} if this list is empty
 566      * @since 1.5
 567      */
 568     public E peek() {
 569         final Node<E> f = first;
 570         return (f == null) ? null : f.item;
 571     }
 572 
 573     /**
 574      * Retrieves, but does not remove, the head (first element) of this list.
 575      *
 576      * @return the head of this list
 577      * @throws NoSuchElementException if this list is empty
 578      * @since 1.5
 579      */
 580     public E element() {
 581         return getFirst();
 582     }
 583 
 584     /**
 585      * Retrieves and removes the head (first element) of this list.
 586      *
 587      * @return the head of this list, or {@code null} if this list is empty
 588      * @since 1.5
 589      */
 590     public E poll() {
 591         final Node<E> f = first;
 592         return (f == null) ? null : unlinkFirst(f);
 593     }
 594 
 595     /**
 596      * Retrieves and removes the head (first element) of this list.
 597      *
 598      * @return the head of this list
 599      * @throws NoSuchElementException if this list is empty
 600      * @since 1.5
 601      */
 602     public E remove() {
 603         return removeFirst();
 604     }
 605 
 606     /**
 607      * Adds the specified element as the tail (last element) of this list.
 608      *
 609      * @param e the element to add
 610      * @return {@code true} (as specified by {@link Queue#offer})
 611      * @since 1.5
 612      */
 613     public boolean offer(E e) {
 614         return add(e);
 615     }
 616 
 617     // Deque operations
 618     /**
 619      * Inserts the specified element at the front of this list.
 620      *
 621      * @param e the element to insert
 622      * @return {@code true} (as specified by {@link Deque#offerFirst})
 623      * @since 1.6
 624      */
 625     public boolean offerFirst(E e) {
 626         addFirst(e);
 627         return true;
 628     }
 629 
 630     /**
 631      * Inserts the specified element at the end of this list.
 632      *
 633      * @param e the element to insert
 634      * @return {@code true} (as specified by {@link Deque#offerLast})
 635      * @since 1.6
 636      */
 637     public boolean offerLast(E e) {
 638         addLast(e);
 639         return true;
 640     }
 641 
 642     /**
 643      * Retrieves, but does not remove, the first element of this list,
 644      * or returns {@code null} if this list is empty.
 645      *
 646      * @return the first element of this list, or {@code null}
 647      *         if this list is empty
 648      * @since 1.6
 649      */
 650     public E peekFirst() {
 651         final Node<E> f = first;
 652         return (f == null) ? null : f.item;
 653      }
 654 
 655     /**
 656      * Retrieves, but does not remove, the last element of this list,
 657      * or returns {@code null} if this list is empty.
 658      *
 659      * @return the last element of this list, or {@code null}
 660      *         if this list is empty
 661      * @since 1.6
 662      */
 663     public E peekLast() {
 664         final Node<E> l = last;
 665         return (l == null) ? null : l.item;
 666     }
 667 
 668     /**
 669      * Retrieves and removes the first element of this list,
 670      * or returns {@code null} if this list is empty.
 671      *
 672      * @return the first element of this list, or {@code null} if
 673      *     this list is empty
 674      * @since 1.6
 675      */
 676     public E pollFirst() {
 677         final Node<E> f = first;
 678         return (f == null) ? null : unlinkFirst(f);
 679     }
 680 
 681     /**
 682      * Retrieves and removes the last element of this list,
 683      * or returns {@code null} if this list is empty.
 684      *
 685      * @return the last element of this list, or {@code null} if
 686      *     this list is empty
 687      * @since 1.6
 688      */
 689     public E pollLast() {
 690         final Node<E> l = last;
 691         return (l == null) ? null : unlinkLast(l);
 692     }
 693 
 694     /**
 695      * Pushes an element onto the stack represented by this list.  In other
 696      * words, inserts the element at the front of this list.
 697      *
 698      * <p>This method is equivalent to {@link #addFirst}.
 699      *
 700      * @param e the element to push
 701      * @since 1.6
 702      */
 703     public void push(E e) {
 704         addFirst(e);
 705     }
 706 
 707     /**
 708      * Pops an element from the stack represented by this list.  In other
 709      * words, removes and returns the first element of this list.
 710      *
 711      * <p>This method is equivalent to {@link #removeFirst()}.
 712      *
 713      * @return the element at the front of this list (which is the top
 714      *         of the stack represented by this list)
 715      * @throws NoSuchElementException if this list is empty
 716      * @since 1.6
 717      */
 718     public E pop() {
 719         return removeFirst();
 720     }
 721 
 722     /**
 723      * Removes the first occurrence of the specified element in this
 724      * list (when traversing the list from head to tail).  If the list
 725      * does not contain the element, it is unchanged.
 726      *
 727      * @param o element to be removed from this list, if present
 728      * @return {@code true} if the list contained the specified element
 729      * @since 1.6
 730      */
 731     public boolean removeFirstOccurrence(Object o) {
 732         return remove(o);
 733     }
 734 
 735     /**
 736      * Removes the last occurrence of the specified element in this
 737      * list (when traversing the list from head to tail).  If the list
 738      * does not contain the element, it is unchanged.
 739      *
 740      * @param o element to be removed from this list, if present
 741      * @return {@code true} if the list contained the specified element
 742      * @since 1.6
 743      */
 744     public boolean removeLastOccurrence(Object o) {
 745         if (o == null) {
 746             for (Node<E> x = last; x != null; x = x.prev) {
 747                 if (x.item == null) {
 748                     unlink(x);
 749                     return true;
 750                 }
 751             }
 752         } else {
 753             for (Node<E> x = last; x != null; x = x.prev) {
 754                 if (o.equals(x.item)) {
 755                     unlink(x);
 756                     return true;
 757                 }
 758             }
 759         }
 760         return false;
 761     }
 762 
 763     /**
 764      * Returns a list-iterator of the elements in this list (in proper
 765      * sequence), starting at the specified position in the list.
 766      * Obeys the general contract of {@code List.listIterator(int)}.<p>
 767      *
 768      * The list-iterator is <i>fail-fast</i>: if the list is structurally
 769      * modified at any time after the Iterator is created, in any way except
 770      * through the list-iterator's own {@code remove} or {@code add}
 771      * methods, the list-iterator will throw a
 772      * {@code ConcurrentModificationException}.  Thus, in the face of
 773      * concurrent modification, the iterator fails quickly and cleanly, rather
 774      * than risking arbitrary, non-deterministic behavior at an undetermined
 775      * time in the future.
 776      *
 777      * @param index index of the first element to be returned from the
 778      *              list-iterator (by a call to {@code next})
 779      * @return a ListIterator of the elements in this list (in proper
 780      *         sequence), starting at the specified position in the list
 781      * @throws IndexOutOfBoundsException {@inheritDoc}
 782      * @see List#listIterator(int)
 783      */
 784     public ListIterator<E> listIterator(int index) {
 785         checkPositionIndex(index);
 786         return new ListItr(index);
 787     }
 788 
 789     private class ListItr implements ListIterator<E> {
 790         private Node<E> lastReturned = null;
 791         private Node<E> next;
 792         private int nextIndex;
 793         private int expectedModCount = modCount;
 794 
 795         ListItr(int index) {
 796             // assert isPositionIndex(index);
 797             next = (index == size) ? null : node(index);
 798             nextIndex = index;
 799         }
 800 
 801         public boolean hasNext() {
 802             return nextIndex < size;
 803         }
 804 
 805         public E next() {
 806             checkForComodification();
 807             if (!hasNext())
 808                 throw new NoSuchElementException();
 809 
 810             lastReturned = next;
 811             next = next.next;
 812             nextIndex++;
 813             return lastReturned.item;
 814         }
 815 
 816         public boolean hasPrevious() {
 817             return nextIndex > 0;
 818         }
 819 
 820         public E previous() {
 821             checkForComodification();
 822             if (!hasPrevious())
 823                 throw new NoSuchElementException();
 824 
 825             lastReturned = next = (next == null) ? last : next.prev;
 826             nextIndex--;
 827             return lastReturned.item;
 828         }
 829 
 830         public int nextIndex() {
 831             return nextIndex;
 832         }
 833 
 834         public int previousIndex() {
 835             return nextIndex - 1;
 836         }
 837 
 838         public void remove() {
 839             checkForComodification();
 840             if (lastReturned == null)
 841                 throw new IllegalStateException();
 842 
 843             Node<E> lastNext = lastReturned.next;
 844             unlink(lastReturned);
 845             if (next == lastReturned)
 846                 next = lastNext;
 847             else
 848                 nextIndex--;
 849             lastReturned = null;
 850             expectedModCount++;
 851         }
 852 
 853         public void set(E e) {
 854             if (lastReturned == null)
 855                 throw new IllegalStateException();
 856             checkForComodification();
 857             lastReturned.item = e;
 858         }
 859 
 860         public void add(E e) {
 861             checkForComodification();
 862             lastReturned = null;
 863             if (next == null)
 864                 linkLast(e);
 865             else
 866                 linkBefore(e, next);
 867             nextIndex++;
 868             expectedModCount++;
 869         }
 870 
 871         final void checkForComodification() {
 872             if (modCount != expectedModCount)
 873                 throw new ConcurrentModificationException();
 874         }
 875     }
 876 
 877     private static class Node<E> {
 878         E item;
 879         Node<E> next;
 880         Node<E> prev;
 881 
 882         Node(Node<E> prev, E element, Node<E> next) {
 883             this.item = element;
 884             this.next = next;
 885             this.prev = prev;
 886         }
 887     }
 888 
 889     /**
 890      * @since 1.6
 891      */
 892     public Iterator<E> descendingIterator() {
 893         return new DescendingIterator();
 894     }
 895 
 896     /**
 897      * Adapter to provide descending iterators via ListItr.previous
 898      */
 899     private class DescendingIterator implements Iterator<E> {
 900         private final ListItr itr = new ListItr(size());
 901         public boolean hasNext() {
 902             return itr.hasPrevious();
 903         }
 904         public E next() {
 905             return itr.previous();
 906         }
 907         public void remove() {
 908             itr.remove();
 909         }
 910     }
 911 
 912     @SuppressWarnings("unchecked")
 913     private LinkedList<E> superClone() {
 914         try {
 915             return (LinkedList<E>) super.clone();
 916         } catch (CloneNotSupportedException e) {
 917             throw new InternalError();
 918         }
 919     }
 920 
 921     /**
 922      * Returns a shallow copy of this {@code LinkedList}. (The elements
 923      * themselves are not cloned.)
 924      *
 925      * @return a shallow copy of this {@code LinkedList} instance
 926      */
 927     public Object clone() {
 928         LinkedList<E> clone = superClone();
 929 
 930         // Put clone into "virgin" state
 931         clone.first = clone.last = null;
 932         clone.size = 0;
 933         clone.modCount = 0;
 934 
 935         // Initialize clone with our elements
 936         for (Node<E> x = first; x != null; x = x.next)
 937             clone.add(x.item);
 938 
 939         return clone;
 940     }
 941 
 942     /**
 943      * Returns an array containing all of the elements in this list
 944      * in proper sequence (from first to last element).
 945      *
 946      * <p>The returned array will be "safe" in that no references to it are
 947      * maintained by this list.  (In other words, this method must allocate
 948      * a new array).  The caller is thus free to modify the returned array.
 949      *
 950      * <p>This method acts as bridge between array-based and collection-based
 951      * APIs.
 952      *
 953      * @return an array containing all of the elements in this list
 954      *         in proper sequence
 955      */
 956     public Object[] toArray() {
 957         Object[] result = new Object[size];
 958         int i = 0;
 959         for (Node<E> x = first; x != null; x = x.next)
 960             result[i++] = x.item;
 961         return result;
 962     }
 963 
 964     /**
 965      * Returns an array containing all of the elements in this list in
 966      * proper sequence (from first to last element); the runtime type of
 967      * the returned array is that of the specified array.  If the list fits
 968      * in the specified array, it is returned therein.  Otherwise, a new
 969      * array is allocated with the runtime type of the specified array and
 970      * the size of this list.
 971      *
 972      * <p>If the list fits in the specified array with room to spare (i.e.,
 973      * the array has more elements than the list), the element in the array
 974      * immediately following the end of the list is set to {@code null}.
 975      * (This is useful in determining the length of the list <i>only</i> if
 976      * the caller knows that the list does not contain any null elements.)
 977      *
 978      * <p>Like the {@link #toArray()} method, this method acts as bridge between
 979      * array-based and collection-based APIs.  Further, this method allows
 980      * precise control over the runtime type of the output array, and may,
 981      * under certain circumstances, be used to save allocation costs.
 982      *
 983      * <p>Suppose {@code x} is a list known to contain only strings.
 984      * The following code can be used to dump the list into a newly
 985      * allocated array of {@code String}:
 986      *
 987      * <pre>
 988      *     String[] y = x.toArray(new String[0]);</pre>
 989      *
 990      * Note that {@code toArray(new Object[0])} is identical in function to
 991      * {@code toArray()}.
 992      *
 993      * @param a the array into which the elements of the list are to
 994      *          be stored, if it is big enough; otherwise, a new array of the
 995      *          same runtime type is allocated for this purpose.
 996      * @return an array containing the elements of the list
 997      * @throws ArrayStoreException if the runtime type of the specified array
 998      *         is not a supertype of the runtime type of every element in
 999      *         this list
1000      * @throws NullPointerException if the specified array is null
1001      */
1002     @SuppressWarnings("unchecked")
1003     public <T> T[] toArray(T[] a) {
1004         if (a.length < size)
1005             a = (T[])java.lang.reflect.Array.newInstance(
1006                                 a.getClass().getComponentType(), size);
1007         int i = 0;
1008         Object[] result = a;
1009         for (Node<E> x = first; x != null; x = x.next)
1010             result[i++] = x.item;
1011 
1012         if (a.length > size)
1013             a[size] = null;
1014 
1015         return a;
1016     }
1017 
1018     private static final long serialVersionUID = 876323262645176354L;
1019 
1020     /**
1021      * Saves the state of this {@code LinkedList} instance to a stream
1022      * (that is, serializes it).
1023      *
1024      * @serialData The size of the list (the number of elements it
1025      *             contains) is emitted (int), followed by all of its
1026      *             elements (each an Object) in the proper order.
1027      */
1028     private void writeObject(java.io.ObjectOutputStream s)
1029         throws java.io.IOException {
1030         // Write out any hidden serialization magic
1031         s.defaultWriteObject();
1032 
1033         // Write out size
1034         s.writeInt(size);
1035 
1036         // Write out all elements in the proper order.
1037         for (Node<E> x = first; x != null; x = x.next)
1038             s.writeObject(x.item);
1039     }
1040 
1041     /**
1042      * Reconstitutes this {@code LinkedList} instance from a stream
1043      * (that is, deserializes it).
1044      */
1045     @SuppressWarnings("unchecked")
1046     private void readObject(java.io.ObjectInputStream s)
1047         throws java.io.IOException, ClassNotFoundException {
1048         // Read in any hidden serialization magic
1049         s.defaultReadObject();
1050 
1051         // Read in size
1052         int size = s.readInt();
1053 
1054         // Read in all elements in the proper order.
1055         for (int i = 0; i < size; i++)
1056             linkLast((E)s.readObject());
1057     }
1058 }

 

 

总结:
(01) LinkedList 实际上是通过双向链表去实现的。
        它包含一个非常重要的内部类:Entry。Entry是双向链表节点所对应的数据结构,它包括的属性有:当前节点所包含的值,上一个节点,下一个节点。
(02) 从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
(03) LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。
(04) LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
(05) 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。

总结起来如下表格:

        第一个元素(头部)                 最后一个元素(尾部)
        抛出异常        特殊值            抛出异常        特殊值
插入    addFirst(e)    offerFirst(e)    addLast(e)        offerLast(e)
移除    removeFirst()  pollFirst()      removeLast()    pollLast()
检查    getFirst()     peekFirst()      getLast()        peekLast()

(06) LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下表的方法等价:

复制代码
队列方法       等效方法
add(e)        addLast(e)
offer(e)      offerLast(e)
remove()      removeFirst()
poll()        pollFirst()
element()     getFirst()
peek()        peekFirst()
复制代码

(07) LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:

栈方法        等效方法
push(e)      addFirst(e)
pop()        removeFirst()
peek()       peekFirst()

 

  • 增
  • addFirst(e)和offerFirst(e): 查的, 说addXxx是继承自List的, offerXxx是来自Queue. 
  • addLast(e)和offerLast(e)
  • 获取: 获取,但不删除元素。
  • getFirst()和peakFirst(): 如果集合为空, 前者抛异常, 后者获取null. 
  • getLast()和peakLast(): 同上
  • 删: 获取,且删除元素。
  • removeFirst()和pollFirst(): 如果集合为空, 前者抛异常, 后者获取null. 
  • remove()和poll(): 同上
  • removeLast()和pollLast(): 同上

第4部分 LinkedList遍历方式

LinkedList遍历方式

LinkedList支持多种遍历方式。建议不要采用随机访问的方式去遍历LinkedList,而采用逐个遍历的方式。
(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

 

for(Iterator iter = list.iterator(); iter.hasNext();)
    iter.next();

(02) 通过快速随机访问遍历LinkedList

int size = list.size();
for (int i=0; i<size; i++) {
    list.get(i);        
}

(03) 通过另外一种for循环来遍历LinkedList

for (Integer integ:list) 
    ;

(04) 通过pollFirst()来遍历LinkedList

while(list.pollFirst() != null)
    ;

(05) 通过pollLast()来遍历LinkedList

while(list.pollLast() != null)
    ;

(06) 通过removeFirst()来遍历LinkedList

try {
    while(list.removeFirst() != null)
        ;
} catch (NoSuchElementException e) {
}

(07) 通过removeLast()来遍历LinkedList

try {
    while(list.removeLast() != null)
        ;
} catch (NoSuchElementException e) {
}

 

测试这些遍历方式效率的代码如下:

  1 /**
  2  * linkedList 
  3  * @ClassName: LinkedList_test_1
  4  * @Description:
  5  * @author Xingle
  6  * @date 2014-5-20 上午9:48:33
  7  * 
  8  */
  9 public class LinkedList_test_1 {
 10 
 11     public static void main(String[] args) {
 12 
 13         // 通过Iterator遍历LinkedList
 14         iteratorLinkedListThruIterator((LinkedList<Integer>) getLinkedList());
 15         // 通过快速随机访问遍历LinkedList
 16         iteratorLinkedListThruForeach((LinkedList<Integer>) getLinkedList());
 17         // 通过for循环的变种来访问遍历LinkedList
 18         iteratorThroughFor2((LinkedList<Integer>) getLinkedList());
 19         // 通过PollFirst()遍历LinkedList
 20         iteratorThroughPollFirst((LinkedList<Integer>) getLinkedList());
 21         // 通过PollLast()遍历LinkedList
 22         iteratorThroughPollLast((LinkedList<Integer>) getLinkedList());
 23         // 通过removeFirst()遍历LinkedList
 24         iteratorThroughRemoveFirst((LinkedList<Integer>) getLinkedList());
 25         // 通过removeLast()遍历LinkedList
 26         iteratorThroughRemoveLast((LinkedList<Integer>) getLinkedList());
 27     }
 28 
 29     /**
 30      * 通过RemoveLast()来遍历LinkedList
 31      * @param
 32      * @return
 33      * @author xingle
 34      * @data 2014-5-22 上午11:59:11
 35      */
 36     private static void iteratorThroughRemoveLast(LinkedList<Integer> list) {
 37         String name = "iteratorThroughRemoveFirst:";
 38         if (list == null)
 39             return;
 40         long start = getCurrentTime();
 41         try {
 42             while (list.removeLast() != null)
 43                 ;
 44         } catch (NoSuchElementException e) {
 45 
 46         }
 47         long end = getCurrentTime();
 48         long interval = end - start;
 49         getPrint(name, interval);
 50 
 51     }
 52 
 53     /**
 54      * 通过RemoveFirst()来遍历LinkedList
 55      * @param
 56      * @return
 57      * @author xingle
 58      * @data 2014-5-22 上午11:58:36
 59      */
 60     private static void iteratorThroughRemoveFirst(LinkedList<Integer> list) {
 61         String name = "iteratorThroughRemoveFirst:";
 62         if (list == null)
 63             return;
 64         long start = getCurrentTime();
 65         try {
 66             while (list.removeFirst() != null)
 67                 ;
 68         } catch (NoSuchElementException e) {
 69         }
 70         long end = getCurrentTime();
 71         long interval = end - start;
 72         getPrint(name, interval);
 73 
 74     }
 75     
 76     
 77 
 78     /**
 79      * 通过pollLast()来遍历LinkedList
 80      * @param
 81      * @return
 82      * @author xingle
 83      * @data 2014-5-22 上午11:57:37
 84      */
 85     private static void iteratorThroughPollLast(LinkedList<Integer> list) {
 86         String name = "iteratorThroughPollLast:";
 87         if (list == null)
 88             return;
 89         long start = getCurrentTime();
 90         while (list.pollLast() != null)
 91             ;
 92         long end = getCurrentTime();
 93         long interval = end - start;
 94         getPrint(name, interval);
 95 
 96     }
 97 
 98     /**
 99      * 通过pollFirst()来遍历LinkedList
100      * @param
101      * @return
102      * @author xingle
103      * @data 2014-5-22 上午11:48:59
104      */
105     private static void iteratorThroughPollFirst(LinkedList<Integer> list) {
106         String name = "iteratorThroughPollFirst:";
107         if (list == null)
108             return;
109         long start = getCurrentTime();
110         while (list.pollFirst() != null)
111             ;
112         long end = getCurrentTime();
113         long interval = end - start;
114         getPrint(name, interval);
115     }
116 
117     /**
118      * 
119      * @Description:
120      * @param
121      * @return
122      * @author xingle
123      * @data 2014-5-22 上午11:54:10
124      */
125     private static void getPrint(String name, long interval) {
126         System.out.println(name + interval + " ms");
127 
128     }
129 
130     /**
131      * 获取当前时间
132      * @Description:
133      * @param
134      * @return
135      * @author xingle
136      * @data 2014-5-22 上午11:50:29
137      */
138     private static long getCurrentTime() {
139         long start = System.currentTimeMillis();
140         return start;
141     }
142 
143     /**
144      * 通过快速随机访问遍历LinkedList
145      * 
146      * @Description:
147      * @param
148      * @return
149      * @author xingle
150      * @data 2014-5-22 上午11:32:33
151      */
152     private static void iteratorThroughFor2(LinkedList<Integer> list) {
153         String name = "iteratorLinkedListByForeachRandomAccess:";
154         if (list == null)
155             return;
156         long start = getCurrentTime();
157         int size = list.size();
158         for (int i = 0; i < size; i++) {
159             list.get(i);
160         }
161         long end = getCurrentTime();
162         long interval = end - start;
163         getPrint(name, interval);
164     }
165 
166     /**
167      * 通过另外一种for循环来遍历LinkedList
168      * 
169      * @Description:
170      * @param
171      * @return
172      * @author xingle
173      * @data 2014-5-22 上午11:32:31
174      */
175     private static void iteratorLinkedListThruForeach(LinkedList<Integer> list) {
176         String name = "iteratorThroughForEach:";
177         if (list == null)
178             return;
179         long start = getCurrentTime();
180         for (Integer i : list)
181             ;
182         long end = getCurrentTime();
183         long interval = end - start;
184         getPrint(name, interval);
185     }
186 
187     /**
188      * 通过快迭代器遍历LinkedList
189      * 
190      * @Description:
191      * @param
192      * @return
193      * @author xingle
194      * @data 2014-5-22 上午11:32:23
195      */
196     private static void iteratorLinkedListThruIterator(LinkedList<Integer> list) {
197         String name = "iteratorLinkedListThruIterator:";
198         if (list == null)
199             return;
200         long start = getCurrentTime();
201 
202         for (Iterator<Integer> iter = list.iterator(); iter.hasNext();)
203             iter.next();
204         long end = getCurrentTime();
205         long interval = end - start;
206         getPrint(name, interval);
207     }
208 
209     /**
210      * 
211      * @Description:
212      * @param
213      * @return
214      * @author xingle
215      * @data 2014-5-22 上午11:31:58
216      */
217     private static Object getLinkedList() {
218         LinkedList<Integer> ls = new LinkedList<>();
219         for (int i = 0; i < 100000; i++)
220             ls.addLast(i);
221 
222         return ls;
223     }
224 
225 }

执行结果:

iteratorLinkedListThruIterator:13 ms
iteratorThroughForEach:9 ms
iteratorLinkedListByForeachRandomAccess:6886 ms
iteratorThroughPollFirst:7 ms
iteratorThroughPollLast:7 ms
iteratorThroughRemoveFirst:5 ms
iteratorThroughRemoveFirst:5 ms

由此可见,遍历LinkedList时,使用removeFist()或removeLast()效率最高。但用它们遍历时,会删除原始数据;若单纯只读取,而不删除,应该使用第3种遍历方式。
无论如何,千万不要通过随机访问去遍历LinkedList!

 


 

转载:http://www.cnblogs.com/skywang12345/p/3308807.html

 

posted on 2014-04-28 09:18  xingle0917  阅读(2966)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3