LinkedList是对链表的扩展,其底层使用链表实现,不是线程安全的集合类。其继承AbstractSequentialList,实现了List, Deque, Cloneable,Serializable各个接口,其中AbstractSequentialList继承了AbstractList抽象类,AbstractList是对支持随机读取的List的部分功能的抽象,AbstractSequentialList是对不支持随机读取的List的一部分功能的抽象。而且LinkedList实现了Deque接口,表明其支持双端队列的全部功能。node
LinkedList首先是链表的扩展,而且实现了双端队列的接口,因此其特色以下:安全
//元素的个数 transient int size = 0; //首节点 transient Node<E> first; //尾节点 transient Node<E> last;
在此以前,先介绍一下双端链表的数据结构数据结构
private static class Node<E> { //节点的值 E item; //下一个节点,若是为尾节点,则此值为null Node<E> next; //前一个节点,若是为首节点,则此值为null Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
//向链表头添加元素 private void linkFirst(E e) { final Node<E> f = first; //设置新节点,令首节点等于新节点,并将新节点的next指向原来的首节点 final Node<E> newNode = new Node<>(null, e, f); first = newNode; //若是原来首节点为空,表明为空链表,则令尾节点也为新节点 ,不然,令原来首节点的前一个节点为新节点 if (f == null) last = newNode; else f.prev = newNode; //元素个数与修改次数进行增长 size++; modCount++; } //向链表尾添加元素 void linkLast(E e) { final Node<E> l = last; //设置新节点,令尾节点指向新节点,而且将新节点的prev指向原来的尾节点 final Node<E> newNode = new Node<>(l, e, null); last = newNode; //若是原来尾节点为空,表明为空链表,则令首节点也为新节点 ,不然,令原来尾节点的下一个节点为新节点 if (l == null) first = newNode; else l.next = newNode; size++; modCount++; } //在给定节点以前插入对应节点 void linkBefore(E e, Node<E> succ) { //获取给定节点的前一个节点,设为pred final Node<E> pred = succ.prev; //设置新节点,令其prev为给定节点的前一个节点,next为给定节点 final Node<E> newNode = new Node<>(pred, e, succ); //同时设置给定节点的前一个节点为新节点 succ.prev = newNode; //判断pred是否为空,若是是,那么新节点就是首节点 ,不然,直接令pred的下一个节点为新节点 if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; } //删除首节点 private E unlinkFirst(Node<E> f) { final E element = f.item; final Node<E> next = f.next; //将首节点中相关引用置空,防止内存泄漏 f.item = null; f.next = null; //令首节点为首节点的下一个节点 first = next; //若是首节点为空,那么直接将尾节点也置空, 不然,将当前首节点的prev置为null if (next == null) last = null; else next.prev = null; size--; modCount++; return element; } //删除尾节点 private E unlinkLast(Node<E> l) { final E element = l.item; final Node<E> prev = l.prev; //将尾节点中相关引用置空,防止内存泄漏 l.item = null; l.prev = null; //令尾节点为尾节点的前一个节点 last = prev; //若是尾节点为空,那么直接将首节点也置空, 不然,将当前尾节点的next置为null if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; } //删除指定元素 E unlink(Node<E> x) { final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; //若是指定节点的前一个节点为空,表明制定节点为首节点 ,令首节点为指定节点的下一个节点,不然,指定节点 的prev的next节点为其自身的next节点,而且令指定节点 的prev节点为null if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } //同理,若是指定节点的下一个节点为null,表明指定节点为尾节点,令 尾节点等于指定节点的上一个节点,不然,指定节点的next节点的prev节点 等于其自身的prev节点,且令自身的next节点等于null if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } //最后,将指定节点的item也置为null,防止内存泄漏 x.item = null; size--; modCount++; return element; } //按照索引值与对应集合类进行批量添加 public boolean addAll(int index, Collection<? extends E> c) { //检验index是否合法,就是检查其是否在[0,size]范围内,若是index为size,就是尾节点 checkPositionIndex(index); Object[] a = c.toArray(); int numNew = a.length; //若是集合类长度为0,那么直接返回失败 if (numNew == 0) return false; //若是index与size大小相等,直接设置插入位置为尾节点 ,不然,进行遍历查找节点,设置查找到的节点的前一个节点为插入节点 Node<E> pred, succ; if (index == size) { succ = null; pred = last; } else { succ = node(index); pred = succ.prev; } //循环插入 for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); //若是pred==null,表明index=0,此时直接插入首节点,令 首节点等于新节点,不然,直接令pred的下一个节点为新节点,而后依序插入 if (pred == null) first = newNode; else pred.next = newNode; pred = newNode; } //若是,succ==null,表明index==size,则是直接从 尾部进行插入,因此,直接令尾节点指向插入的最后一个节点便可 ,不然,令最后一个插入节点的next等于succ, 令succ的prev等于最后一个插入节点便可(其实就是进行了一个衔接) if (succ == null) { last = pred; } else { pred.next = succ; succ.prev = pred; } //对元素数量进行增长 size += numNew; modCount++; return true; } //根据索引查找对应的节点(调用这个方法的方法已经判断过index,因此直接使用) Node<E> node(int index) { //若是index靠近左边,从first开始遍历,不然,从last开始遍历 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; } }