LinkedList基于源码理解
LinkedList 和 ArrayList是最经常拿来进行比较的两个List实现,Linked一听就知道是链表,所以他的增删均是不需要大动干戈的,使得效率很高,同样的Array标识一个数据,查询效率高但是增删效率低下。
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、链表节点样子
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; } }
4、关键方法
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;//返回数组 }
add()
public boolean add(E e) { linkLast(e); return true; }
void linkLast(E e) { final Node<E> l = last; //将尾部节点赋值节点I final Node<E> newNode = new Node<>(l, e, null);//以尾部节点为新节点的前置节点 last = newNode;//将尾部节点的值变成刚插入的值 if (l == null) first = newNode;//若原链表为空链表,需要额外更新头结点 else l.next = newNode;//否则更新原尾节点的后置节点为现在的尾节点(新节点) size++;//size变大 modCount++;//链表修改次数 }
remove()
public boolean remove(Object o) { if (o == null) { //如果要删除的是null节点(从remove和add 里 可以看出,允许元素为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); return true; } } } return false; }
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) { //如果后置节点为null,说明是尾节点 last = prev; } else {//否则更新 后置节点的前置节点 next.prev = prev; x.next = null;//否则更新 后置节点的前置节点 } x.item = null;//否则更新 后置节点的前置节点 size--; modCount++; return element;//返回删除的元素值 }
addAll
public boolean addAll(int index, Collection<? extends E> c) { checkPositionIndex(index); //检查是否越界 Object[] a = c.toArray();//拿到目标集合数组 int numNew = a.length;//判断数组数量 if (numNew == 0)//如果数据等于0 就返回 return false; Node<E> pred, succ; //定义前置节点和后置节点,直接在链表尾部增加数据 if (index == size) { succ = null; pred = last; } else { succ = node(index);//取出index节点,作为后置节点 pred = succ.prev;//前置节点是,index节点的前一个节点 } for (Object o : a) {//带便利的节点 @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null);//以前置节点 和 元素值e,构建new一个新节点, if (pred == null) first = newNode;//如果前置节点是空,说明是头结点 else pred.next = newNode;//否则 前置节点的后置节点设置问新节点 pred = newNode; } if (succ == null) { last = pred; } else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++; return true; }