java1.7集合源码阅读:LinkedList
Posted jessezeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java1.7集合源码阅读:LinkedList相关的知识,希望对你有一定的参考价值。
先看看类定义:
1 public class LinkedList<E> 2 extends AbstractSequentialList<E> 3 implements List<E>, Deque<E>, Cloneable, java.io.Serializable 4 { 5 ....... 6 }
LinkedList与ArrayList相比,LinkedList不再实现RandomAccess接口,表明不支持快速随机访问数据,但实现了Deque接口,可当队列使用,Deque继承自Queue,接口定义:
1 public interface Queue<E> extends Collection<E> { 2 void addFirst(E e); 3 void addLast(E e); 4 boolean offerFirst(E e); 5 boolean offerLast(E e); 6 E removeFirst(); 7 E removeLast(); 8 E pollFirst(); 9 E pollLast(); 10 E getFirst(); 11 E getLast(); 12 E peekFirst(); 13 E peekLast(); 14 boolean removeFirstOccurrence(Object o); 15 boolean removeLastOccurrence(Object o); 16 boolean add(E e); 17 boolean offer(E e); 18 E remove(); 19 E poll(); 20 E element(); 21 E peek(); 22 void push(E e); 23 boolean remove(Object o); 24 boolean contains(Object o); 25 public int size(); 26 Iterator<E> iterator(); 27 Iterator<E> descendingIterator();
28 }
看看LinkedList的两个属性,一个头节点,一个末节点:
1 /** 2 * Pointer to first node. 3 * Invariant: (first == null && last == null) || 4 * (first.prev == null && first.item != null) 5 */ 6 transient Node<E> first; 7 8 /** 9 * Pointer to last node. 10 * Invariant: (first == null && last == null) || 11 * (last.next == null && last.item != null) 12 */ 13 transient Node<E> last;
在看看Node的定义:
1 private static class Node<E> { 2 E item; 3 Node<E> next; 4 Node<E> prev; 5 6 Node(Node<E> prev, E element, Node<E> next) { 7 this.item = element; 8 this.next = next; 9 this.prev = prev; 10 } 11 }
Node中保存着存入集合的对象,同时也保存着上一个节点和下一个节点,由此可知,LinkedList 内部采用的是双向链表结构。
再看看CRUD操作:
add:
1 /** 2 * Appends the specified element to the end of this list. 3 * 4 * <p>This method is equivalent to {@link #addLast}. 5 * 6 * @param e element to be appended to this list 7 * @return {@code true} (as specified by {@link Collection#add}) 8 */ 9 public boolean add(E e) { 10 linkLast(e); //last节点后拼接一个节点 11 return true; 12 } 13 /** 14 * Links e as last element. 15 */ 16 void linkLast(E e) { 17 final Node<E> l = last; 18 final Node<E> newNode = new Node<>(l, e, null); 19 last = newNode; // 将last节点指向当前新创建的节点,新节点变为last节点,原last节点的下一个节点指向最新的last节点
20 if (l == null)
21 first = newNode;
22 else
23 l.next = newNode;
24 size++;
25 modCount++;
26 }
与linkLast对应的还有linkFirst:
1 /** 2 * Links e as first element. 3 */将元素添加到首节点 4 private void linkFirst(E e) { 5 final Node<E> f = first; 6 final Node<E> newNode = new Node<>(null, e, f); 7 first = newNode; 8 if (f == null) 9 last = newNode; 10 else 11 f.prev = newNode; 12 size++; 13 modCount++; 14 }
既然存在在对尾、队尾添加元素,那么是不是也应该存在在指定某个元素之前或之后添加元素呢,是的,的确存在:
1 /** 2 * Inserts element e before non-null Node succ. 3 */ 4 void linkBefore(E e, Node<E> succ) { 5 // assert succ != null; 6 final Node<E> pred = succ.prev; 7 final Node<E> newNode = new Node<>(pred, e, succ); 8 succ.prev = newNode; 9 if (pred == null) 10 first = newNode; 11 else 12 pred.next = newNode; 13 size++; 14 modCount++; 15 }
与此同时也还存在另外两个方法,一个是在指定节点位置添加元素,另一个是将指定位置的元素修改成当前元素:
1 /** 2 * Replaces the element at the specified position in this list with the 3 * specified element. 4 * 5 * @param index index of the element to replace 6 * @param element element to be stored at the specified position 7 * @return the element previously at the specified position 8 * @throws IndexOutOfBoundsException {@inheritDoc} 9 */ 10 public E set(int index, E element) { //指定位置的元素修改成当前元素 11 checkElementIndex(index); 12 Node<E> x = node(index); 13 E oldVal = x.item; 14 x.item = element; 15 return oldVal; 16 } 17 18 /** 19 * Inserts the specified element at the specified position in this list. 20 * Shifts the element currently at that position (if any) and any 21 * subsequent elements to the right (adds one to their indices). 22 * 23 * @param index index at which the specified element is to be inserted 24 * @param element element to be inserted 25 * @throws IndexOutOfBoundsException {@inheritDoc} 26 */ 27 public void add(int index, E element) { //指定节点位置添加元素 28 checkPositionIndex(index); 29 30 if (index == size) 31 linkLast(element); 32 else 33 linkBefore(element, node(index)); 34 }
linkedList 虽然提供了get(index) 方法,但并不没有ArrayList那样高效的获取,而是变量整个数据结构,此时,做了一个优化,根据index判断元素是在链表的前端还是后端,如果是后端,则从队尾开始遍历:
1 /** 2 * Returns the element at the specified position in this list. 3 * 4 * @param index index of the element to return 5 * @return the element at the specified position in this list 6 * @throws IndexOutOfBoundsException {@inheritDoc} 7 */ 8 public E get(int index) { 9 checkElementIndex(index); 10 return node(index).item; 11 } 12 /** 13 * Returns the (non-null) Node at the specified element index. 14 */ 15 Node<E> node(int index) { 16 // assert isElementIndex(index); 17 18 if (index < (size >> 1)) { 19 Node<E> x = first; 20 for (int i = 0; i < index; i++) 21 x = x.next; 22 return x; 23 } else { 24 Node<E> x = last; 25 for (int i = size - 1; i > index; i--) 26 x = x.prev; 27 return x; 28 } 29 }
获取对首或队尾元素就简单了,直接返回对首或队尾元素就ok了:
1 /** 2 * Returns the first element in this list. 3 * 4 * @return the first element in this list 5 * @throws NoSuchElementException if this list is empty 6 */ 7 public E getFirst() { 8 final Node<E> f = first; 9 if (f == null) 10 throw new NoSuchElementException(); 11 return f.item; 12 } 13 14 /** 15 * Returns the last element in this list. 16 * 17 * @return the last element in this list 18 * @throws NoSuchElementException if this list is empty 19 */ 20 public E getLast() { 21 final Node<E> l = last; 22 if (l == null) 23 throw new NoSuchElementException(); 24 return l.item; 25 }
LinkedList 无参remove方法,是直接删除队首元素:
1 /** 2 * Retrieves and removes the head (first element) of this list. 3 * 4 * @return the head of this list 5 * @throws NoSuchElementException if this list is empty 6 * @since 1.5 7 */ 8 public E remove() { 9 return removeFirst(); 10 } 11 /** 12 * Removes and returns the first element from this list. 13 * 14 * @return the first element from this list 15 * @throws NoSuchElementException if this list is empty 16 */ 17 public E removeFirst() { 18 final Node<E> f = first; 19 if (f == null) 20 throw new NoSuchElementException(); 21 return unlinkFirst(f); 22 } 23 /** 24 * Unlinks non-null first node f. 25 */ 26 private E unlinkFirst(Node<E> f) { //将对首元素设置null,将对首的下一元素作为对首元素 27 // assert f == first && f != null; 28 final E element = f.item; 29 final Node<E> next = f.next; 30 f.item = null; 31 f.next = null; // help GC 32 first = next; 33 if (next == null) 34 last = null; 35 else 36 next.prev = null; 37 size--; 38 modCount++; 39 return element; 40 }
remove(Object),变量整个数据结构删除:
1 /** 2 * Removes the first occurrence of the specified element from this list, 3 * if it is present. If this list does not contain the element, it is 4 * unchanged. More formally, removes the element with the lowest index 5 * {@code i} such that 6 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 7 * (if such an element exists). Returns {@code true} if this list 8 * contained the specified element (or equivalently, if this list 9 * changed as a result of the call). 10 * 11 * @param o element to be removed from this list, if present 12 * @return {@code true} if this list contained the specified element 13 */ 14 public boolean remove(Object o) { 15 if (o == null) {//先判断是否是空值 16 for (Node<E> x = first; x != null; x = x.next) { 17 if (x.item == null) { 18 unlink(x); 19 return true; 20 } 21 } 22 } else { 23 for (Node<E> x = first; x != null; x = x.next) { 24 if (o.equals(x.item)) { 25 unlink(x); 26 return true; 27 } 28 } 29 } 30 return false; 31 }
linkedList实现了队列接口,使用中也可以直接当队列用:
1 /** 2 * Adds the specified element as the tail (last element) of this list. 3 * 4 * @param e the element to add 5 * @return {@code true} (as specified by {@link Queue#offer}) 6 * @since 1.5 7 */ 8 public boolean offer(E e) { 9 return add(e); 10 } 11 12 // Deque operations 13 /** 14 * Inserts the specified element at the front of this list. 15 * 16 * @param e the element to insert 17 * @return {@code true} (as specified by {@link Deque#offerFirst}) 18 * @since 1.6 19 */ 20 public boolean offerFirst(E e) { 21 addFirst(e); 22 return true; 23 } 24 25 /** 26 * Inserts the specified element at the end of this list. 27 * 28 * @param e the element to insert 29 * @return {@code true} (as specified by {@link Deque#offerLast}) 30 * @since 1.6 31 */ 32 public boolean offerLast(E e) { 33 addLast(e); 34 return true; 35 }
linkedList 还提供了几个方法,可以直接通过peek方法获取元素,需要注意的是获取之后并不会从队列中删除该元素:
1 /** 2 * Retrieves, but does not remove, the first element of this list, 3 * or returns {@code null} if this list is empty. 4 * 5 * @return the first element of this list, or {@code null} 6 * if this list is empty 7 * @since 1.6 8 */ 9 public E peekFirst() { 10 final Node<E> f = first; 11 return (f == null) ? null : f.item; 12 } 13 14 /** 15 * Retrieves, but does not remove, the last element of this list, 16 * or returns {@code null} if this list is empty. 17 * 18 * @return the last element of this list, or {@code null} 19 * if this list is empty 20 * @since 1.6 21 */ 22 public E peekLast() { 23 final Node<E> l = last; 24 return (l == null) ? null : l.item; 25 }
与peek对应的还有poll方法,同样是获取元素,不同点在于,获取元素之后,该元素将会从队列中删除。
1 /** 2 * Retrieves and removes the first element of this list, 3 * or returns {@code null} if this list is empty. 4 * 5 * @return the first element of this list, or {@code null} if 6 * this list is empty 7 * @since 1.6 8 */ 9 public E pollFirst() { 10 final Node<E> f = first; 11 return (f == null) ? null : unlinkFirst(f); 12 } 13 14 /** 15 * Retrieves and removes the last element of this list, 16 * or returns {@code null} if this list is empty. 17 * 18 * @return the last element of this list, or {@code null} if 19 * this list is empty 20 * @since 1.6 21 */ 22 public E pollLast() { 23 final Node<E> l = last; 24 return (l == null) ? null : unlinkLast(l); 25 }
LinkedList提供了多种操作数据集合的方法,但最重要的一点就是,整个是实现是非线程安全的,在多线程下需要进行同步处理,或者使用并发包中的对应实现类。
以上是关于java1.7集合源码阅读:LinkedList的主要内容,如果未能解决你的问题,请参考以下文章
jdk源码阅读笔记之java集合框架(LinkedList)
JDK1.8JDK1.8集合源码阅读——LinkedList
JAVA 集合类(java.util)源码阅读笔记------LinkedList