【JDK1.6源码阅读】LinkedList
2014-11-19 23:10
344 查看
1.概述
LinkedList是List的接口实现类,实现了所有可选的list操作且允许所有的元素(包括null值)。除了实现List接口之外,LinkedList类提供了统一的命名方法为了在列表的头部和尾部get、remove、insert元素。这些操作允许链表可以作为stack(栈)、Queue(队列)、Deque(双端队列)。LinkedList也实现了Deque接口,为add、poll(轮询?)和其他stack、deque方法提供了先进先出(first-in-first-out)队列操作。
所有的这些操作实现作为双向列表是可被预估到的。,无论是不是接近指定的索引,这些操作都会从表头或表尾开始轮询链表。
注意,这些实现并不是同步的。如果多个线程同时访问一个链表,至少有一个线程结构上修改链表,那必须表面上看起来是同步的。(结构上的修改是指添加或删除一个或多个元素,仅仅设置一个元素的值并不是结构上的修改)。这可以非常典型地通过同步自然封装列表的某些对象达到。
如果没有这样的对象存在,列表就应该用Collections.synchronizedLis方法t来封装。为了偶然地不同步访问列表,这个应该在创建的时候就被做了。
List list = Collections.synchronizedList(new LinkedList(...));
LinkedList类的迭代器和迭代方法返回的迭代器都是快速失败的(fail-fast),所以在迭代器被创立之后,如果对列表进行结构性的修改,除非通过迭代器本身的remove方法,迭代器都会抛出一个ConcurrentModificationException异常。因此,面对并发修改,迭代器很快就会完全失败,而不冒在将来不确定的时间发生任意不确定行为的风险。
注意,迭代器的快速失败行为不能得到保证,一般来说,存在非同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的做法是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。
2.数据结构
<span style="white-space:pre"> </span>private transient Entry<E> header = new Entry<E>(null, null, null); <span style="white-space:pre"> </span>private transient int size = 0;
<span style="white-space:pre"> </span>private static class Entry<E> { <span style="white-space:pre"> </span>E element; <span style="white-space:pre"> </span>Entry<E> next; <span style="white-space:pre"> </span>Entry<E> previous; <span style="white-space:pre"> </span>Entry(E element, Entry<E> next, Entry<E> previous) { <span style="white-space:pre"> </span> this.element = element; <span style="white-space:pre"> </span> this.next = next; <span style="white-space:pre"> </span> this.previous = previous; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span> }
从源码上可以看出,LinkedList就是一个双向链表。实体定义为元素、上一entry、下一entry。
LinkedList有一个头entry,头元素的next指向第一个entry,previous指向最后一个entry。
3.存取操作
(1)containspublic boolean contains(Object o) { return indexOf(o) != -1; } public int indexOf(Object o) { int index = 0; if (o==null) { for (Entry e = header.next; e != header; e = e.next) { if (e.element==null) return index; index++; } } else { for (Entry e = header.next; e != header; e = e.next) { if (o.equals(e.element)) return index; index++; } } return -1; }判断一个对象是否在linkedList中,就是找出这个对象在linkedList中的索引位置,如果找不到,返回-1.
(2)add:插入列表尾部
public boolean add(E e) { addBefore(e, header); return true; } private Entry<E> addBefore(E e, Entry<E> entry) { Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; size++; modCount++; return newEntry; }add(E e):默认插入头entry之前,创建一个待插入的新entry,next指向头entry,previous指向连表末尾。插入的操作就是,把原链表末尾entry的next指向新entry,头entry的previous指向新entry,同时把size增加1,modCount增加1。
(3)add:指定位置插入
public void add(int index, E element) { addBefore(element, (index==size ? header : entry(index))); }
add(int index, E element):如果待插入位置的索引等于链表的大小,就是要插入链表的尾部,与add(E e)方法相同。
如果不是插入尾部,而是插入链表其他位置,就要根据索引找出所在位置的entry(查找方法,下面会有讲解)。创建一个待插入的新entry,next指向原index位置的entry,previous指向原index-1位置的entry;原index-1位置的entry的next指向新entry,原index位置的previous指向新entry。这样index-1位置的entry没变,index位置变成了新entry,原index位置的entry变成了index+1。
(4)remove
public boolean remove(Object o) { if (o==null) { for (Entry<E> e = header.next; e != header; e = e.next) { if (e.element==null) { remove(e); return true; } } } else { for (Entry<E> e = header.next; e != header; e = e.next) { if (o.equals(e.element)) { remove(e); return true; } } } return false; }
private E remove(Entry<E> e) { if (e == header) throw new NoSuchElementException(); E result = e.element; e.previous.next = e.next; e.next.previous = e.previous; e.next = e.previous = null; e.element = null; size--; modCount++; return result; }
移除列表中首先出现的指定的元素,如果没出现,列表将不会变化。
从头entry开始查找,查找到与指定元素相等的entry,然后移除这个entry;把待移除entry的上一个entry的next指向entry的下一个entry,待移除的entry的下一个entry的previous指向待移除entry的上一个entry,然后把待移除的entry置为null,size大小减1,modCount增加1。
相关文章推荐
- JDK源码阅读-LinkedList
- 阅读String源码总结【jdk1.6】
- jdk源码阅读——linkedlist
- [JDK1.7源码阅读]LinkedList
- 【JDK源码阅读4-util】Collection-List---LinkedList
- JDK1.8源码阅读系列之二:LinkedList
- jdk源码阅读二:LinkedList
- jdk源码阅读笔记-LinkedList
- JDK1.8源码阅读之——VECTOR,ARRAYLIST, LINKEDLIST
- Java Collections Framework之Stack源码分析缺陷,栈改进版(通过LinkedList实现)(基于JDK1.6)
- 给jdk写注释系列之jdk1.6容器(12):PriorityQueue源码解析PriorityQueue是一种什么样的容器呢?看过前面的几个jdk容器分析的话,看到Queue这个单词你一定会,哦~这
- jdk源码阅读-Map
- java核心基础--jdk源码分析学习--LinkedList
- JDK源码阅读之Object类
- 【JDK1.8】JDK1.8集合源码阅读——IdentityHashMap
- JDK源码阅读(二) AbstractList
- 给jdk写注释系列之jdk1.6容器(4)-HashMap源码解析
- Vector源码阅读(JDK 8)
- JDK源码阅读之Queue接口和Deque接口
- 阅读JDK源码有感