Collection容器初探之LinkedList
2017-09-13 18:07
309 查看
网上的LinkedList的源码分析大都为JDK1.6的版本,所以为双向循环链表的环形结构。但是JDK1.7的版本为双向链表。
先简单分析了解下JDK1.6版本的源码:
参考:
给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析
这篇博客分析的很彻底!!!赞。
JDK1.6~JDK1.7过程中,LinkedList从双向循环链表转换为双向链表
这次来简单了解和分析下JDK1.6的基于双向循环链表的实现:
![](http://img.blog.csdn.net/20170913175442614?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzI0NjgyMjU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
继承自List,Deque,Cloneable,Serializible接口
双向循环链表的底层数据存储形式:
其中size为元素数目,header为链表的头节点,Entry为链表中的节点对象
经常使用的默认构造方法:
Entry为LinkedList的静态内部类,定义了当前存储的节点和它相邻的两个节点:
插入:
![](http://img.blog.csdn.net/20170913180221791?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzI0NjgyMjU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
删除:
查询:
改动:
先简单分析了解下JDK1.6版本的源码:
参考:
给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析
这篇博客分析的很彻底!!!赞。
JDK1.6~JDK1.7过程中,LinkedList从双向循环链表转换为双向链表
这次来简单了解和分析下JDK1.6的基于双向循环链表的实现:
继承自List,Deque,Cloneable,Serializible接口
public class LinkedList extends AbstractSequentialList implements List, Deque, Cloneable, java.io.Serializable
双向循环链表的底层数据存储形式:
private transient Entry header = new Entry(null, null, null); private transient int size = 0;
其中size为元素数目,header为链表的头节点,Entry为链表中的节点对象
经常使用的默认构造方法:
public LinkedList() { //将header节点的前一节点和后一节点都设置为自身 header.next = header.previous = header; }
Entry为LinkedList的静态内部类,定义了当前存储的节点和它相邻的两个节点:
private static class Entry { E element; Entry next; Entry previous; Entry(E element, Entry next, Entry previous) { this.element = element; this.next = next; this.previous = previous; } }
插入:
/** * 添加一个集合元素到list中 */ public boolean addAll(Collection<? extends E> c) { // 将集合元素添加到list最后的尾部 return addAll(size , c); } /** * 在指定位置添加一个集合元素到list中 */ public boolean addAll(int index, Collection<? extends E> c) { // 越界检查 if (index < 0 || index > size) throw new IndexOutOfBoundsException( "Index: "+index+ ", Size: "+size ); Object[] a = c.toArray(); // 要插入元素的个数 int numNew = a.length ; if (numNew==0) return false; modCount++; // 找出要插入元素的前后节点 // 获取要插入index位置的下一个节点,如果index正好是lsit尾部的位置那么下一个节点就是header,否则需要查找index位置的节点 Entry<E> successor = (index== size ? header : entry(index)); // 获取要插入index位置的上一个节点,因为是插入,所以上一个点击就是未插入前下一个节点的上一个 Entry<E> predecessor = successor. previous; // 循环插入 for (int i=0; i<numNew; i++) { // 构造一个节点,确认自身的前后引用 Entry<E> e = new Entry<E>((E)a[i], successor, predecessor); // 将插入位置上一个节点的下一个元素引用指向当前元素(这里不修改下一个节点的上一个元素引用,是因为下一个节点随着循环一直在变) predecessor. next = e; // 最后修改插入位置的上一个节点为自身,这里主要是为了下次遍历后续元素插入在当前节点的后面,确保这些元素本身的顺序 predecessor = e; } // 遍历完所有元素,最后修改下一个节点的上一个元素引用为遍历的最后一个元素 successor. previous = predecessor; // 修改计数器 size += numNew; return true; }
删除:
/** * 删除第一个匹配的指定元素 */ public boolean remove(Object o) { // 遍历链表找到要被删除的节点 if (o==null) { for (Entry e = header .next; e != header; e = e.next ) { if (e.element ==null) { remove(e); return true; } } } else { for (Entry e = header .next; e != header; e = e.next ) { if (o.equals(e.element )) { remove(e); return true; } } } return false; } private E remove(Entry e) { if (e == header ) throw new NoSuchElementException(); // 被删除的元素,供返回 E result = e. element; // 下面修正前后对该节点的引用 // 将该节点的上一个节点的next指向该节点的下一个节点 e. previous.next = e.next; // 将该节点的下一个节点的previous指向该节点的上一个节点 e. next.previous = e.previous; // 修正该节点自身的前后引用 e. next = e.previous = null; // 将自身置空,让gc可以尽快回收 e. element = null; // 计数器减一 size--; modCount++; return result; }
查询:
/** * 查找指定索引位置的元素 */ public E get( int index) { return entry(index).element ; } /** * 返回指定索引位置的节点 */ private Entry<E> entry( int index) { // 越界检查 if (index < 0 || index >= size) throw new IndexOutOfBoundsException( "Index: "+index+ ", Size: "+size ); // 取出头结点 Entry<E> e = header; // size>>1右移一位代表除以2,这里使用简单的二分方法,判断index与list的中间位置的距离 if (index < (size >> 1)) { // 如果index距离list中间位置较近,则从头部向后遍历(next) for (int i = 0; i <= index; i++) e = e. next; } else { // 如果index距离list中间位置较远,则从头部向前遍历(previous) for (int i = size; i > index; i--) e = e. previous; } return e; }
改动:
/** * 修改指定位置索引位置的元素 */ public E set( int index, E element) { // 查找index位置的节点 Entry e = entry(index); // 取出该节点的元素,供返回使用 E oldVal = e. element; // 用新元素替换旧元素 e. element = element; // 返回旧元素 return oldVal; }
相关文章推荐
- Collection容器之List初探
- java容器---Collection{list{LinkedList ,ArrayList,Vector},Set}
- Java 容器:Collection 初探之 List
- java容器类分析:Collection,List,ArrayList,LinkedList深入解读
- 容器Collection的总结一 Vector ArrayList LinkedList HashSet TreeSet
- Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比较
- 集合与数组的比较、Collection与Collections的区别、ArrayList与LinkedList区别、Vector与ArrayList区别、HashMap与Hashtable
- 容器第一课,容器的基本概念,Collection、set、List接口介绍
- 容器源码分析之LinkedList(三)
- day08-集合【LinkedList、HashSet、Collection集合体系】
- Java 容器 & 泛型(2):ArrayList 、LinkedList和Vector比较
- 深入理解容器系列之三--------LinkedList、Stack、Queue、PriorityQueue的总结
- Java 集合:Collection,List,ArrayList,Vector,LinkedList(实现方式,对比)
- 【C#学习笔记】LinkedList容器使用
- 初探LinkedList线程安全问题
- 容器第四课,JDK源代码分析,自己实现LinkedList,双向链表的概念_节点定义
- JDK容器与并发—List—LinkedList
- Collection- List、set-- ArrayList LinkedList Vector,早年笔记
- 集合Collection中ArrayList、LinkedList、Vector的用法详解
- 【转】java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别