基于jdk_1.8.0

关于List,主要是有序的可重复的数据结构。jdk主要实现类有ArrayList(底层使用数组)、LinkedList(底层使用双向链表)

  LinkedList:

  (一)继承关系图

    

  (二)源码分析

    1. 关键字段 

 /**
* 当前链表元素个数
*/
transient int size = 0; /**
* 指向第一个节点的指针
*/
transient Node<E> first; /**
* 指向最后一个节点的指针
*/
transient Node<E> last;

    2. 构造方法

    

 public LinkedList() {
} public LinkedList(Collection<? extends E> c) {
this();
addAll(c); //详见 3. public boolean addAll(Collection<? extends E> c)
}

    3. 常用方法

      a. public boolean add(E e)

 /**
* 向链表的尾部追加元素
* 等效于调用addLast方法,只不过addLast没有返回值
* @param e
* @return
*/
public boolean add(E e) {
linkLast(e);
return true;
} /**
* 链表尾部追加元素
* 第一个添加的元素节点作为链表的头结点
* @param e
*/
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null); // 构造新的node节点
last = newNode; //尾节点指向新节点
if (l == null)
first = newNode; //空表时,头节点也指向新节点
else
l.next = newNode; //将新节点添加到链表
size++;
modCount++;
} // LinkedList$Node.class
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;
}
}

      b. public void add(int index, E element)

 /**
* 将指定的元素插入到列表中的指定位置。
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException
*/
public void add(int index, E element) {
checkPositionIndex(index); if (index == size)
linkLast(element); // 详见 a. public void add(E element)
else
linkBefore(element, node(index));
} private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
} private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
} /**
* 在 succ节点前插入
* @param e
* @param succ
*/
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); // newNode.prev = pred; newNode.next = succ;
succ.prev = newNode; //更新succ的前继节点
if (pred == null)
first = newNode; // 在第一个元素节点前插入,更新头节点
else
pred.next = newNode; //将新节点加入链表
size++;
modCount++;
} /**
* 最坏的情况需要遍历size/2个节点找到 index位置的节点
* @param index
* @return
*/
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;
}
}

      c. public boolean addAll(Collection<? extends E> c)

 /**
* 将指定集合中的所有元素追加到链表
* 默认尾插
* @param c collection containing elements to be added to this list
* @return {@code true} if this list changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c); //详见 4. public boolean addAll(int index, Collection<? extends E> c)
}

      d. public boolean addAll(int index, Collection<? extends E> c)

 /**
* 从指定位置开始插入,性能不如尾插
* 虽然说,链表的随机插入较快,但是node(int index) 最坏也要遍历size/2个节点才能找到该位置的节点
* @param index index at which to insert the first element
* from the specified collection
* @param c collection containing elements to be added to this list
* @return {@code true} if this list changed as a result of the call
* @throws IndexOutOfBoundsException {@inheritDoc}
* @throws NullPointerException if the specified collection is null
*/
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index); // index < 0 || index > size throws IndexOutOfBoundsException Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false; Node<E> pred, succ;
if (index == size) { // 尾插(包括空表情况)
succ = null;
pred = last; // 待插入节点的前继节点
} else {
succ = node(index); // 获取index位置的节点
pred = succ.prev; // 待插入节点的前继节点
} for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null); // newNode.prev = pred; newNode.next = null;
if (pred == null) //空表更新头节点
first = newNode;
else
pred.next = newNode; //更新前继节点的next指向当前新节点
pred = newNode;
} if (succ == null) { // 空表更新尾节点
last = pred;
} else {
pred.next = succ; // 更新最后添加新节点的后继节点为原index位置节点
succ.prev = pred; // 更新原index位置节点的前继节点为最后新添加元素的节点
} size += numNew;
modCount++;
return true;
}

      e. public void addFirst(E e) // override for Deque

 /**
* 头插法,对应的就是尾插法 addLast(E e)
* 头插,尾插性能想同,不过默认的add(E e)使用的是尾插法
* @param e
*/
public void addFirst(E e) {
linkFirst(e);
} private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}

      f. public void addLast(E e) // override for Deque

 /**
* 尾插法,对应的头插法 addFirst(E e),性能想同
* @param e
*/
public void addLast(E e) {
linkLast(e);
} 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++;
}

      g. public E remove()   // override for Deque

 /**
* 从链表中移除并返回第一个元素。
* @return
*/
public E remove() {
return removeFirst();
} /**
* 从链表中移除并返回第一个元素。
*
* @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);
} /**
* 该方法并没有判断参数是否null并且为第一个节点 需要调用者去保证
* 不过不理解的地方是,明明有first成员变量,为什么还要当做参数传进来
* @param f 头节点
* @return 移除掉的元素
*/
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;
}

      h. public E remove(int index)

 /**
* 移除列表中指定位置的元素
*
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
} /**
* 从链表中移除节点x
* @param x
* @return x.item
*/
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) { // x为第一个节点
first = next;
} else {
prev.next = next; // 把待移除节点的前继节点的next指向待移除节点的next
x.prev = null;
} if (next == null) { // x为最后一个节点
last = prev;
} else {
next.prev = prev; // 把待移除节点的后继节点的prev指向待移除节点的prev
x.next = null;
} x.item = null;
size--;
modCount++;
return element;
}

      i. public boolean remove(Object o)

 /**
* 删除第一个存在链表中的 o
*
* @param o element to be removed from this list, if present
* @return {@code true} if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x); //移除x节点 详情 h. public E remove(int index)
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x); //移除x节点 详情 h. public E remove(int index)
return true;
}
}
}
return false;
}

      j. public E set(int index, E element)

 /**
* 更新指定位置的元素
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
checkElementIndex(index); // index < 0 || index >= size throws IndexOutOfBoundsException
Node<E> x = node(index); // 获取index位置的节点
E oldVal = x.item;
x.item = element;
return oldVal;
}

      k. public E get(int index)

 /**
* 获取链表指定位置的元素
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
checkElementIndex(index); // index < 0 || index >= size throws IndexOutOfBoundsException
return node(index).item;
}

      l. public int indexOf(Object o)

 /**
* 查找链表中元素o所在的第一个下标
*
* @param o element to search for
* @return the index of the first occurrence of the specified element in
* this list, or -1 if this list does not contain the element
*/
public int indexOf(Object o) {
int index = 0;
if (o == null) {
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)) // 需要重写实体类的equals方法
return index;
index++;
}
}
return -1;
}

      m. public int lastIndexOf(Object o)

 /**
* 从后往前遍历查找元素o所在的位置
*
* @param o element to search for
* @return the index of the last occurrence of the specified element in
* this list, or -1 if this list does not contain the element
*/
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;
}

      n. public Iterator<E> iterator() //AbstractSequentialList.class

 // LinkedList ——> AbstractSequentialList ——> AbstractList

     // AbstractSequentialList.class
public Iterator<E> iterator() {
return listIterator(); // AbstractList.listIterator()
} public abstract ListIterator<E> listIterator(int index); // AbstractList.class
public ListIterator<E> listIterator() {
return listIterator(0); // LinkedList.listIterator(0)
} // LinkedList.class
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
} // LinkedList$ListItr.class
private class ListItr implements ListIterator<E> {
/**
* 主要是提供给 remove、set方法用,在调用remove、set方法前 务必首先调用next() 或者 previous,否则lastReturned为null 会抛IllegalStateException
* 也要注意调用remove、add方法后lastReturned会置为null
*/
private Node<E> lastReturned; // next() 或者 previous()返回的最新节点
private Node<E> next; // 当前游标节点
private int nextIndex; // 当前游标位置
private int expectedModCount = modCount; ListItr(int index) {
// assert isPositionIndex(index);
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; //第一个节点没有前继节点
} /**
* 调用previous()要小心默认 listIterator() {
* listIterator(0); // 此种情况下使用hasPrevious()遍历,返回的永远都是false
* }
* 对应next() 应调用listIterator(list.size())
* @return
*/
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; // 防止再次remove
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); // 在next节点前插入e
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();
} /**
* 防止使用iterator遍历的时候,还操作list
*/
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

      o. public ListIterator<E> listIterator(int index)

 /**
* 指定从index位置开始遍历链表
* 如果使用previous ,必须调用该方法,指定index > 0
* @param index
* @return
*/
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index); //参考 n. public Iterator<E> iterator()
}

      p. public Object[] toArray()

 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;
}

      q. public <T> T[] toArray(T[] a)

 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;
}

      r. 其他基本方法

 /**
* 清空列表
*/
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
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;
size = 0;
modCount++;
} /**
* 克隆列表 ,需要实体类自行重写Object.clone()方法,才可实现深度复制
* @return
*/
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;
} /**
* 列表是否包含元素o
* @param o
* @return
*/
public boolean contains(Object o) {
return indexOf(o) != -1;
} /**
* 当前列表节点数量
* @return
*/
public int size() {
return size;
} // 序列化相关
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());
} 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 (LinkedList.Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
}

      s. Deque方法

 public void addFirst(E e) {
linkFirst(e);
} public void addLast(E e) {
linkLast(e);
} public E element() {
return getFirst();
} 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;
} public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
} public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
} public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
} public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
} public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
} public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
} public E pop() {
return removeFirst();
} public void push(E e) {
addFirst(e);
} public E remove() {
return removeFirst();
} public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
} public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
} public boolean removeFirstOccurrence(Object o) {
return remove(o);
} 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;
}

写在最后:

  通过构造方法,还有add方法,可以看出,没有构造没有存储任何元素的头结点,第一个存储的元素作为链表的头结点;

  通过Node内部类prev,next可以看出LinkedList是双向链表,既可以从尾部向头部遍历,也可以从头部向尾部遍历;

  非必要情况下,尽可能不要调用按位置插入方法,会多一步按位置查找节点影响性能。对于插入时选择头插法还是尾插法,性能都是一样的。默认add(E e) 调用的是addLast;

  通过对比ArrayList,发现LinkedList除了实现了AbstractList还实现了Deque,可以把LinkedList当做队列、栈操作,比如addFirst、addLast、remove、pop、push等;

  使用listIterator.hasPrevious()从后往前遍历的时候,应注意list.listIterator(list.size());

  LinkedList理论上只要内存足够,几乎没有最大元素上限;

  和ArrayList一样,LinkedList也是非线程安全的,存放其中的实体,同样也需要重写Object.equals()方法。如果需要调用list.clone(),还应重写Object.clone()方法;

  LinkedList,在随机插入由于不需要移动元素,故比ArrayList要快,但在get(int index)、set(int index, E e)随机访问要比ArrayList慢

  

java集合LinkedList的更多相关文章

  1. Java 集合 LinkedList的ListIterator

    Java 集合 LinkedList的ListIterator @author ixenos 摘要:ListIterator<E>是继承自Iterator<E>的接口.list ...

  2. 6.Java集合-LinkedList实现原理及源码分析

    Java中LinkedList的部分源码(本文针对1.7的源码) LinkedList的基本结构 jdk1.7之后,node节点取代了 entry ,带来的变化是,将1.6中的环形结构优化为了直线型链 ...

  3. Java集合---LinkedList源码解析

    一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clo ...

  4. Java集合 LinkedList的原理及使用

    Java集合 LinkedList的原理及使用 LinkedList和ArrayList一样是集合List的实现类,虽然较之ArrayList,其使用场景并不多,但同样有用到的时候,那么接下来,我们来 ...

  5. Java集合-LinkedList源码分析

    目录 1.数据结构-链表 2.ArrayList结构特性 3.构造方法 4.成员变量 5.常用的成员方法 6.Node节点 7.序列化原理 8.迭代器 9.总结 1.数据结构-链表 链表(Linked ...

  6. java集合-LinkedList

    一.概述 LinkedList 与 ArrayList 一样实现 List 接口,只是 ArrayList 是 List 接口的大小可变数组的实现,LinkedList 是 List 接口链表的实现. ...

  7. Java 集合 - LinkedList

    一.源码解析 (1). 属性 // 链表长度 transient int size = 0; // 链首和链尾 transient Node<E> first; transient Nod ...

  8. Java集合——LinkedList源码详解

    )LinkedList直接继承于AbstractSequentialList,同时实现了List接口,也实现了Deque接口. AbstractSequentialList为顺序访问的数据存储结构提供 ...

  9. Java集合:LinkedList源码解析

    Java集合---LinkedList源码解析   一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据re ...

随机推荐

  1. Verilog 位拼接运算符的优先级

    最近研究FIFO的时候,在开源工程中看到这样一段代码 ; always @(posedge rd_clk) {'b0}}; else {'b0}}; else if(re) rp_bin <= ...

  2. C语言第四次实验

    这次实验共计7道题目 以下代码亲测无误 1.用选择排序法,键盘输入10个整数,对10个整数进行排序(升序) 1.第一种思路就是常规思路,输入--排序--输出 源代码如下: //常规思路,输入,排序,输 ...

  3. 2015306 白皎 《网络攻防》Exp3 免杀原理与实践

    2015306 白皎 <网络攻防>Exp3 免杀原理与实践 一.实践基础 免杀,故名思义,指的是一种能使病毒木马免于被杀毒软件查杀的技术. 免杀的方法有很多,比如加壳改壳.加垃圾指令.以及 ...

  4. JavaScript总结(七)

    JavaScript表单编程 表单是Web上与用户进行交互的主要界面.则我们需要掌握如何访问用户输入的表单数据,校验用户输入的正确性显得至关重要. ♞ 对Form元素进行脚本编写 ✍ 获取表单的应用 ...

  5. matplotlib绑定到PyQt5(有菜单)

    稍微复杂地实现matplotlib绑定到PyQt5(有菜单) [知识点] import matplotlib matplotlib.use("Qt5Agg") [效果图] [源代码 ...

  6. QtWidgets Module's Classes

    Qt Widgets C++ Classes The Qt Widgets module extends Qt GUI with C++ widget functionality. More... A ...

  7. tomcat : 虚拟路径映射

    tomcat设置虚拟访问地址和真实路径的映射,方法有几种,这里介绍常用的两种方式: 一.修改server.xml文件: 步骤如下:  1.在tomcat根目录下打开conf文件夹,该文件夹下有个ser ...

  8. C#两个引用类的属性、方法 各位早安

    ***字符串.IndexOf("串"); - 返回字符串中第一个匹配项的索引,如果没有匹配项返回-1  intint b = s.IndexOf("天",s.I ...

  9. 【译】Serverless架构 - 3

    原文: https://martinfowler.com/articles/serverless.html 消息驱动型应用 后台数据处理服务是一个不同的例子. 你要写一个需要快速响应UI请求的以用户为 ...

  10. 读书笔记:《HTML5开发手册》--figure、time、details、mark

    这是补充HTML5基础知识的系列内容,其他为: 一.HTML5-- 新的结构元素 二.HTML5-- figure.time.details.mark 三.HTML5-- details活学活用 四. ...