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

时间:2022-04-12 17:20:49

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关系如下图:

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

 

第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的队列时,下表的方法等价:

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例
队列方法       等效方法
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()
Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

(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