双向循环链表

双向循环链表和双向链表的不同在于,第一个节点的pre指向最后一个节点,最后一个节点的next指向第一个节点,也形成一个“环”。而LinkedList就是基于双向循环链表设计的。

LinkedList 的继承关系

LinkedList 是一个继承于AbstractSequentialList的双向循环链表。它也可以被当作堆栈、队列或双端队列进行操作。

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

LinkedList 实现 List 接口,能对它进行队列操作。

LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。

LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。

LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。

LinkedList 是非同步的。

LinkedList属性:

size:当前有多少个节点;

first:第一个节点;

last:最后一个节点;

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//list的元素数量
transient int size = 0; /**
*第一个节点
*/
transient Node<E> first; /**
* 最后一个节点
*/
transient Node<E> last;

LinkedList构造方法:

​ 空的构造方法:表示初始化的时候,size为默认值0;first和last为空;

​ 带入参的构造方法:

  1. this()调用默认无参构造方法;
  2. addAll()传进去入参的集合数据;
  3. 检查index索引范围 ;
  4. 得到集合数据
  5. 得到插入位置的前驱和后继节点
  6. 遍历数据,将数据插入到指定位置
 /**
* 空构造函数
*/
public LinkedList() {
} /**
*构造一个包含指定 collection 中的元素的列表,这些元素按其 collection 的迭代器返回的顺序排列
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
 /**
* 将集合从指定位置开始插入
* 1. 检查index索引范围
* 2. 得到集合数据
* 3. 得到插入位置的前驱和后继节点
* 4. 遍历数据,将数据插入到指定位置
*/
public boolean addAll(int index, Collection<? extends E> c) {
//检查index范围
checkPositionIndex(index);
//得到集合的数据
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
//得到插入位置的前驱节点和后继节点
Node<E> pred, succ;
//位置为尾部,前驱节点为last,后继节点为null
if (index == size) {
succ = null;
pred = last;
} else {
//调用node()方法得到后继节点,再得到前驱节点
succ = node(index);
pred = succ.prev;
}
//遍历数据将数据插入
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
//创建新节点
Node<E> newNode = new Node<>(pred, e, null);
//前置节点为空,插入位置在链表头部
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
//如果插入位置在尾部,重置last节点
if (succ == null) {
last = pred;
} else {
//否则,将插入的链表与先前链表连接起来
pred.next = succ;
succ.prev = pred;
} size += numNew;
modCount++;
return true;
}

新增元素操作:

/**
* 将一个元素添加至list尾部
*/
public boolean add(E e) {
linkLast(e);
return true;
}

指定位置添加元素:

  1. 检查index的范围,否则抛出异常
  2. 如果插入位置是链表尾部,那么调用linkLast方法
  3. 如果插入位置是链表中间,那么调用linkBefore方法
/**
* 指定位置添加元素
*1. 检查index的范围,否则抛出异常
*2. 如果插入位置是链表尾部,那么调用linkLast方法
*3. 如果插入位置是链表中间,那么调用linkBefore方法
*/
public void add(int index, E element) {
//检查索引是否处于[0-size]之间
checkPositionIndex(index);
//添加在链表尾部
if (index == size)
linkLast(element);
else
//添加在链表中间
linkBefore(element, node(index));
}

linkBefore 非空节点前插入元素图示:

检索操作总结:

检索操作分为按照位置得到对象以及按照对象得到位置两种方式,其中按照对象得到位置的方法有indexOf()和lastIndexOf();按照位置得到对象有如下方法:

  • 根据任意位置得到数据的get(int index)方法,当index越界会抛出异常
  • 获得头节点数据
  • getFirst()和element()方法在链表为空时会抛出NoSuchElementException
  • peek()和peekFirst()方法在链表为空时会返回null
  • 获得尾节点数据
  • getLast()在链表为空时会抛出NoSuchElementException
  • peekLast()在链表为空时会返回null

get方法:

 /**
* 检索指定位置元素,索引越界,抛出异常
*/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
    /**
* 返回指定位置的非空节点
*/
Node<E> node(int index) {
// assert isElementIndex(index);
//如果索引位置靠链表前半部分,从头开始遍历
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//否则,从尾开始遍历
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}

getFirst操作和getLast操作:

    /**
* Returns the first element in this list.
*
* @return the first element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getFirst() {
final Node<E> f = first;
if (f == null)
//链表为null,抛出异常
throw new NoSuchElementException();
return f.item;
} /**
* 链表为空时,会抛出NoSuchElementException
*/
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}

删除操作总结

删除操作由很多种方法,有:

  • 按照指定对象删除:boolean remove(Object o),一次只会删除一个匹配的对象
  • 按照指定位置删除
  • 删除任意位置的对象:E remove(int index),当index越界时会抛出异常
  • 删除头节点位置的对象
  • 在链表为空时抛出异常:E remove()、E removeFirst()、E pop()
  • 在链表为空时返回null:E poll()、E pollFirst()
  • 删除尾节点位置的对象
  • 在链表为空时抛出异常:E removeLast()
  • 在链表为空时返回null:E pollLast()
remove()方法:

移除第一个节点,将第一个节点置空,让下一个节点变成第一个节点,链表长度减1,修改次数加1,返回移除的第一个节点。

/**
* 在链表为空时将抛出NoSuchElementException
*/
public E remove() {
return removeFirst();
}

removeFirst()方法:

  /**
* Removes and returns the first element from this list.
*
* @return the first element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
    /**
* Unlinks non-null first node f.
*/
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
//第一个节点置空
f.item = null;
f.next = null; // help GC
//下一个节点变成第一个节点
first = next;
if (next == null)
last = null;
else
next.prev = null;
//链表长度减1
size--;
//修改次数加1
modCount++;
return element;
}
remove(int index)方法:

删除任意位置的元素,如果删除成功将返回true,否则返回false

    1. 检查index范围,属于[0,size)
    1. 将索引出节点删除
/**
* 删除任意位置的元素,如果删除成功将返回true,否则返回false
* 1. 检查index范围,属于[0,size)
* 2. 将索引出节点删除
*/
public E remove(int index) {
//检查index范围
checkElementIndex(index);
//将节点删除
return unlink(node(index));
}

set方法:

 public E set(int index, E element) {
//检查index是否越界
checkElementIndex(index);
//索引index位置的节点
Node<E> x = node(index);
//index位置的节点内容替换为element
E oldVal = x.item;
x.item = element;
//返回原来旧的值
return oldVal;
}

clear方法:

 public void clear() {
//遍历链表,置空链表元素
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
//修改链表长度为0
size = 0;
//修改次数加一
modCount++;
}

listIterator方法:

    /**
* 在ListIterator的构造器中,得到了当前位置的节点,就是变量next。next()方法返回当前节点的值并将 *next指向其后继节点,previous()方法返回当前节点的前一个节点的值并将next节点指向其前驱节点。由于 *Node是一个双端节点,所以这儿用了一个节点就可以实现从前向后迭代和从后向前迭代。另外在 *ListIterator初始时,exceptedModCount保存了当前的modCount,如果在迭代期间,有操作改变了链表 *的底层结构,那么再操作迭代器的方法时将会抛出ConcurrentModificationException。
*/
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}

LinkedList 源码解析:

节点对象:

/**
*节点对象
*/
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;
}
}
package java.util;

import java.util.function.Consumer;

public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
//list的元素数量
transient int size = 0; /**
*第一个节点
*/
transient Node<E> first; /**
* 最后一个节点
*/
transient Node<E> last; /**
* 空构造函数
*/
public LinkedList() {
} /**
*构造一个包含指定 collection 中的元素的列表,这些元素按其 collection 的迭代器返回的顺序排列
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
} /**
* Links e as first element.
*/
private void linkFirst(E e) {
final Node<E> f = first;
//新建节点,以头节点为后继节点
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
//如果链表为空,last节点也指向该节点
if (f == null)
last = newNode;
else
//否则,将头节点的前驱指针指向新节点
f.prev = newNode;
size++;
modCount++;
} /**
* Links e as last element.
*/
void linkLast(E e) {
//指向链表尾部
final Node<E> l = last;
//以尾部为前驱节点创建一个新节点
final Node<E> newNode = new Node<>(l, e, null);
//将链表尾部指向新节点
last = newNode;
//如果链表为空,那么该节点既是头节点也是尾节点
if (l == null)
first = newNode;
else
l.next = newNode;
//增加集合大小
size++;
modCount++;
} /**
* 非空节点前插入元素
* 1. 创建newNode节点,将newNode的后继指针指向succ,前驱指针指向pred
* 2. 将succ的前驱指针指向newNode
* 3. 根据pred是否为null,进行不同操作。
* - 如果pred为null,说明该节点插入在头节点之前,要重置first头节点
* - 如果pred不为null,那么直接将pred的后继指针指向newNode即可
*/
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
} /**
* Unlinks non-null first node f.
*/
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
} /**
* Unlinks non-null last node l.
*/
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
} /**
* 从链表中移除元素
* 1 得到待删除节点的前驱节点和后继节点
* 2 删除前驱节点
* 3 删除后继节点
*/
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
//后继节点
final Node<E> next = x.next;
//前驱节点
final Node<E> prev = x.prev; //删除前驱指针
if (prev == null) {
//如果删除的节点是头节点,令头节点指向该节点的后继节点
first = next;
} else {
//将前驱节点的后继节点指向后继节点
prev.next = next;
x.prev = null;
} //删除后继指针
if (next == null) {
//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点
last = prev;
} else {
next.prev = prev;
x.next = null;
} x.item = null;
size--;
modCount++;
return element;
} /**
* Returns the first element in this list.
*
* @return the first element in this list
* @throws NoSuchElementException if this list is empty
*/
public E getFirst() {
final Node<E> f = first;
if (f == null)
//链表为null,抛出异常
throw new NoSuchElementException();
return f.item;
} /**
* 链表为空时,会抛出NoSuchElementException
*/
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
} /**
* Removes and returns the first element from this list.
*
* @return the first element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
} /**
* Removes and returns the last element from this list.
*
* @return the last element from this list
* @throws NoSuchElementException if this list is empty
*/
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
} /**
*list头部添加指定元素
*/
public void addFirst(E e) {
linkFirst(e);
} /**
* 将元素添加到链表尾部,与add()方法一样。所以实现也一样
*/
public void addLast(E e) {
linkLast(e);
} /**
* 检查对象o是否存在于链表中
*/
public boolean contains(Object o) {
//返回结果不是-1,那就说明该对象存在于链表中
return indexOf(o) != -1;
} /**
* Returns the number of elements in this list.
*
* @return the number of elements in this list
*/
public int size() {
return size;
} /**
* 将一个元素添加至list尾部
*/
public boolean add(E e) {
linkLast(e);
return true;
} /**
* 删除指定元素
*/
public boolean remove(Object o) {
//如果删除对象为null
if (o == null) {
//从前向后遍历
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
//从前向后遍历
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
//匹配返回true
return true;
}
}
}
return false;
} /**
* 将集合插入到链表尾部,即开始索引位置为size
*/
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
} /**
* 将集合从指定位置开始插入
* 1. 检查index索引范围
* 2. 得到集合数据
* 3. 得到插入位置的前驱和后继节点
*4. 遍历数据,将数据插入到指定位置
*/
public boolean addAll(int index, Collection<? extends E> c) {
//检查index范围
checkPositionIndex(index);
//得到集合的数据
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
//得到插入位置的前驱节点和后继节点
Node<E> pred, succ;
//位置为尾部,前驱节点为last,后继节点为null
if (index == size) {
succ = null;
pred = last;
} else {
//调用node()方法得到后继节点,再得到前驱节点
succ = node(index);
pred = succ.prev;
}
//遍历数据将数据插入
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
//创建新节点
Node<E> newNode = new Node<>(pred, e, null);
//前置节点为空,插入位置在链表头部
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
//如果插入位置在尾部,重置last节点
if (succ == null) {
last = pred;
} else {
//否则,将插入的链表与先前链表连接起来
pred.next = succ;
succ.prev = pred;
} size += numNew;
modCount++;
return true;
} public void clear() {
//遍历链表,置空链表元素
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
//修改链表长度为0
size = 0;
//修改次数加一
modCount++;
} /**
* 检索指定位置元素,索引越界,抛出异常
*/
public E get(int index) {
checkElementIndex(index);
return node(index).item;
} public E set(int index, E element) {
//检查index是否越界
checkElementIndex(index);
//索引index位置的节点
Node<E> x = node(index);
//index位置的节点内容替换为element
E oldVal = x.item;
x.item = element;
//返回原来旧的值
return oldVal;
} /**
* 指定位置添加元素
*1. 检查index的范围,否则抛出异常
*2. 如果插入位置是链表尾部,那么调用linkLast方法
*3. 如果插入位置是链表中间,那么调用linkBefore方法
*/
public void add(int index, E element) {
//检查索引是否处于[0-size]之间
checkPositionIndex(index);
//添加在链表尾部
if (index == size)
linkLast(element);
else
//添加在链表中间
linkBefore(element, node(index));
} /**
* 删除任意位置的元素,如果删除成功将返回true,否则返回false
* 1. 检查index范围,属于[0,size)
* 2. 将索引出节点删除
*/
public E remove(int index) {
//检查index范围
checkElementIndex(index);
//将节点删除
return unlink(node(index));
} /**
* Tells if the argument is the index of an existing element.
*/
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
} /**
* Tells if the argument is the index of a valid position for an
* iterator or an add operation.
*/
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
} /**
* Constructs an IndexOutOfBoundsException detail message.
* Of the many possible refactorings of the error handling code,
* this "outlining" performs best with both server and client VMs.
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
} private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
} private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
} /**
* 返回指定位置的非空节点
*/
Node<E> node(int index) {
// assert isElementIndex(index);
//如果索引位置靠链表前半部分,从头开始遍历
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//否则,从尾开始遍历
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
} // Search Operations /**
*返回第一个匹配的索引
*/
public int indexOf(Object o) {
int index = 0;
if (o == null) {
//从头往后遍历,元素为空的时候的检索,此处可以观察到LinkedList是支持空元素的
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
//从头往后遍历,元素不为空的时候的检索
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
} /**
*返回最后一个匹配的索引
*/
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
//从后向前遍历,元素为空,返回
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
//从后向前遍历,元素不为空,匹配的情况下返回
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
} // Queue operations. /**
* Retrieves, but does not remove, the head (first element) of this list.
*
* @return the head of this list, or {@code null} if this list is empty
* @since 1.5
*/
public E peek() {
final Node<E> f = first;
//不会抛出异常,但是会返回null
return (f == null) ? null : f.item;
} /**
* Retrieves, but does not remove, the head (first element) of this list.
*
* @return the head of this list
* @throws NoSuchElementException if this list is empty
* @since 1.5
*/
public E element() {
return getFirst();
} /**
* 在链表为空时将返回null
*/
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
} /**
* 在链表为空时将抛出NoSuchElementException
*/
public E remove() {
return removeFirst();
} /**
* 将数据添加到链表尾部,其内部调用了add(E e)方法
*/
public boolean offer(E e) {
return add(e);
} /**
*将数据插入链表头部
*/
public boolean offerFirst(E e) {
addFirst(e);
return true;
} /**
* 数据添加到链表尾部
*/
public boolean offerLast(E e) {
addLast(e);
return true;
} /**
* Retrieves, but does not remove, the first element of this list,
* or returns {@code null} if this list is empty.
*
* @return the first element of this list, or {@code null}
* if this list is empty
* @since 1.6
*/
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
} /**
* 为空,返回null,不会抛异常
*/
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
} /**
* Retrieves and removes the first element of this list,
* or returns {@code null} if this list is empty.
*
* @return the first element of this list, or {@code null} if
* this list is empty
* @since 1.6
*/
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
} /**
* 链表为空时会返回null,而不是抛出异常
*/
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
} /**
* Pushes an element onto the stack represented by this list. In other
* words, inserts the element at the front of this list.
*
* <p>This method is equivalent to {@link #addFirst}.
*
* @param e the element to push
* @since 1.6
*/
public void push(E e) {
addFirst(e);
} /**
* 在链表为空时将抛出NoSuchElementException
*/
public E pop() {
return removeFirst();
} /**
* Removes the first occurrence of the specified element in this
* list (when traversing the list from head to tail). If the list
* does not contain the element, it is unchanged.
*
* @param o element to be removed from this list, if present
* @return {@code true} if the list contained the specified element
* @since 1.6
*/
public boolean removeFirstOccurrence(Object o) {
return remove(o);
} /**
* 链表为空时将抛出NoSuchElementException
*/
public boolean removeLastOccurrence(Object o) {
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
} /**
* 在ListIterator的构造器中,得到了当前位置的节点,就是变量next。next()方法返回当前节点的值并将 *next指向其后继节点,previous()方法返回当前节点的前一个节点的值并将next节点指向其前驱节点。由于 *Node是一个双端节点,所以这儿用了一个节点就可以实现从前向后迭代和从后向前迭代。另外在 *ListIterator初始时,exceptedModCount保存了当前的modCount,如果在迭代期间,有操作改变了链表 *的底层结构,那么再操作迭代器的方法时将会抛出ConcurrentModificationException。
*/
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
} private class ListItr implements ListIterator<E> {
private Node<E> lastReturned;
private Node<E> next;
private int nextIndex;
//保存当前modCount,确保fail-fast机制
private int expectedModCount = modCount; ListItr(int index) {
// assert isPositionIndex(index);
//得到当前索引指向的next节点
next = (index == size) ? null : node(index);
nextIndex = index;
} public boolean hasNext() {
return nextIndex < size;
}
/**
*获取下一个节点
*/
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException(); lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
} public boolean hasPrevious() {
return nextIndex > 0;
} /**
*获取前一个节点,将next节点向前移
*/
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException(); lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
} public int nextIndex() {
return nextIndex;
} public int previousIndex() {
return nextIndex - 1;
} public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException(); Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
} public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
} public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
} public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
} final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
/**
*节点对象
*/
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;
}
} /**
* @since 1.6
*/
public Iterator<E> descendingIterator() {
return new DescendingIterator();
} /**
* Adapter to provide descending iterators via ListItr.previous
*/
private class DescendingIterator implements Iterator<E> {
private final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
} @SuppressWarnings("unchecked")
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
} /**
* Returns a shallow copy of this {@code LinkedList}. (The elements
* themselves are not cloned.)
*
* @return a shallow copy of this {@code LinkedList} instance
*/
public Object clone() {
LinkedList<E> clone = superClone(); // Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0; // Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item); return clone;
} /**
* Returns an array containing all of the elements in this list
* in proper sequence (from first to last element).
*
* <p>The returned array will be "safe" in that no references to it are
* maintained by this list. (In other words, this method must allocate
* a new array). The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all of the elements in this list
* in proper sequence
*/
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
} /**
* Returns an array containing all of the elements in this list in
* proper sequence (from first to last element); the runtime type of
* the returned array is that of the specified array. If the list fits
* in the specified array, it is returned therein. Otherwise, a new
* array is allocated with the runtime type of the specified array and
* the size of this list.
*
* <p>If the list fits in the specified array with room to spare (i.e.,
* the array has more elements than the list), the element in the array
* immediately following the end of the list is set to {@code null}.
* (This is useful in determining the length of the list <i>only</i> if
* the caller knows that the list does not contain any null elements.)
*
* <p>Like the {@link #toArray()} method, this method acts as bridge between
* array-based and collection-based APIs. Further, this method allows
* precise control over the runtime type of the output array, and may,
* under certain circumstances, be used to save allocation costs.
*
* <p>Suppose {@code x} is a list known to contain only strings.
* The following code can be used to dump the list into a newly
* allocated array of {@code String}:
*
* <pre>
* String[] y = x.toArray(new String[0]);</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
*
* @param a the array into which the elements of the list are to
* be stored, if it is big enough; otherwise, a new array of the
* same runtime type is allocated for this purpose.
* @return an array containing the elements of the list
* @throws ArrayStoreException if the runtime type of the specified array
* is not a supertype of the runtime type of every element in
* this list
* @throws NullPointerException if the specified array is null
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item; if (a.length > size)
a[size] = null; return a;
} private static final long serialVersionUID = 876323262645176354L; /**
* Saves the state of this {@code LinkedList} instance to a stream
* (that is, serializes it).
*
* @serialData The size of the list (the number of elements it
* contains) is emitted (int), followed by all of its
* elements (each an Object) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject(); // Write out size
s.writeInt(size); // Write out all elements in the proper order.
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
} /**
* Reconstitutes this {@code LinkedList} instance from a stream
* (that is, deserializes it).
*/
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject(); // Read in size
int size = s.readInt(); // Read in all elements in the proper order.
for (int i = 0; i < size; i++)
linkLast((E)s.readObject());
} /**
* Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
* and <em>fail-fast</em> {@link Spliterator} over the elements in this
* list.
*
* <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
* {@link Spliterator#ORDERED}. Overriding implementations should document
* the reporting of additional characteristic values.
*
* @implNote
* The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}
* and implements {@code trySplit} to permit limited parallelism..
*
* @return a {@code Spliterator} over the elements in this list
* @since 1.8
*/
@Override
public Spliterator<E> spliterator() {
return new LLSpliterator<E>(this, -1, 0);
} /** A customized variant of Spliterators.IteratorSpliterator */
static final class LLSpliterator<E> implements Spliterator<E> {
static final int BATCH_UNIT = 1 << 10; // batch array size increment
static final int MAX_BATCH = 1 << 25; // max batch array size;
final LinkedList<E> list; // null OK unless traversed
Node<E> current; // current node; null until initialized
int est; // size estimate; -1 until first needed
int expectedModCount; // initialized when est set
int batch; // batch size for splits LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
this.list = list;
this.est = est;
this.expectedModCount = expectedModCount;
} final int getEst() {
int s; // force initialization
final LinkedList<E> lst;
if ((s = est) < 0) {
if ((lst = list) == null)
s = est = 0;
else {
expectedModCount = lst.modCount;
current = lst.first;
s = est = lst.size;
}
}
return s;
} public long estimateSize() { return (long) getEst(); } public Spliterator<E> trySplit() {
Node<E> p;
int s = getEst();
if (s > 1 && (p = current) != null) {
int n = batch + BATCH_UNIT;
if (n > s)
n = s;
if (n > MAX_BATCH)
n = MAX_BATCH;
Object[] a = new Object[n];
int j = 0;
do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
current = p;
batch = j;
est = s - j;
return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
}
return null;
} public void forEachRemaining(Consumer<? super E> action) {
Node<E> p; int n;
if (action == null) throw new NullPointerException();
if ((n = getEst()) > 0 && (p = current) != null) {
current = null;
est = 0;
do {
E e = p.item;
p = p.next;
action.accept(e);
} while (p != null && --n > 0);
}
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
} public boolean tryAdvance(Consumer<? super E> action) {
Node<E> p;
if (action == null) throw new NullPointerException();
if (getEst() > 0 && (p = current) != null) {
--est;
E e = p.item;
current = p.next;
action.accept(e);
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
return false;
} public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
} }

LinkedList(JDK1.8)源码分析的更多相关文章

  1. 集合之HashSet(含JDK1.8源码分析)

    一.前言 我们已经分析了List接口下的ArrayList和LinkedList,以及Map接口下的HashMap.LinkedHashMap.TreeMap,接下来看的是Set接口下HashSet和 ...

  2. 【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)

    一.前言 分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet ...

  3. 【JUC】JDK1.8源码分析之ArrayBlockingQueue(三)

    一.前言 在完成Map下的并发集合后,现在来分析ArrayBlockingQueue,ArrayBlockingQueue可以用作一个阻塞型队列,支持多任务并发操作,有了之前看源码的积累,再看Arra ...

  4. 【集合框架】JDK1.8源码分析之HashMap(一) 转载

    [集合框架]JDK1.8源码分析之HashMap(一)   一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...

  5. 【集合框架】JDK1.8源码分析之ArrayList详解(一)

    [集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...

  6. 集合之TreeSet(含JDK1.8源码分析)

    一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...

  7. 集合之LinkedHashSet(含JDK1.8源码分析)

    一.前言 上篇已经分析了Set接口下HashSet,我们发现其操作都是基于hashMap的,接下来看LinkedHashSet,其底层实现都是基于linkedHashMap的. 二.linkedHas ...

  8. 【1】【JUC】JDK1.8源码分析之ArrayBlockingQueue,LinkedBlockingQueue

    概要: ArrayBlockingQueue的内部是通过一个可重入锁ReentrantLock和两个Condition条件对象来实现阻塞 注意这两个Condition即ReentrantLock的Co ...

  9. 【1】【JUC】JDK1.8源码分析之ReentrantLock

    概要: ReentrantLock类内部总共存在Sync.NonfairSync.FairSync三个类,NonfairSync与FairSync类继承自Sync类,Sync类继承自AbstractQ ...

  10. ArrayList、LinkedList和Vector源码分析

    ArrayList.LinkedList和Vector源码分析 ArrayList ArrayList是一个底层使用数组来存储对象,但不是线程安全的集合类 ArrayList的类结构关系 public ...

随机推荐

  1. 【转】Java基础——容器分类

    Java容器可以说是增强程序员编程能力的基本工具,本系列将带您深入理解容器类. 容器的用途 如果对象的数量与生命周期都是固定的,自然我们也就不需要很复杂的数据结构. 我们可以通过创建引用来持有对象,如 ...

  2. SCP传送文件时提示No ECDSA host key is known forx.x.x.x and you have requested strict checking.问题的解决办法

    在使用SCP向其他设备传送文件时,打印如下错误: No ECDSA host key is known for x.x.x.x and you have requested strict checki ...

  3. k8s使用Glusterfs动态生成pv

    一.环境介绍 [root@k8s-m ~]# cat /etc/hosts127.0.0.1 localhost localhost.localdomain localhost4 localhost4 ...

  4. java 环境变量配置 详解!

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. python好文章

    http://blog.csdn.net/csdnnews/article/details/78557392

  6. 用MyEclipse自带工具生成WebService客户端代码

    本文章主要是介绍如何利用已经发布了的Webservice的wsdl来自动生成java的客户端代码.注意:本方法需要你采用的java版本是1.5或者以上的版本,采用MyEclipse来自动生成代码. w ...

  7. Windows 7 quick launch

    %AppData%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar %AppData%\Microsoft\Internet ...

  8. nargin

    nargin 编辑 nargin为“number of input arguments”的缩写. 在matlab中定义一个函数时, 在函数体内部, nargin是用来判断输入变量个数的函数.在matl ...

  9. avpicture_fill的实现

    简介 avpicture_fill函数将ptr指向的数据填充到picture内,但并没有拷贝,只是将picture结构内的data指针指向了ptr的数据.其实现如下: avpiture_fill av ...

  10. winFormToMysql&&几个控件的数据绑定

    运行图: 代码: private void button1_Click(object sender, EventArgs e) { string str = "database=csharp ...