linkedList主要要注意以下几点:
1构造器
2 添加add(E e)
3 获取get(int index)
4 删除 remove(E e),remove(int index)
5 判断对象是否存在:contain(E e)
Jdk8中的linkedList基于双向链表来实现的
双向链表每个结点包含数据域,一个前指针和一个后指针,分别指向前驱结点和后继结点(如果有前驱/后继的话,没有就是null)。
另外,双向链表还有一个first指针,指向头节点,和last指针,指向尾节点。
接下来我们来看看源码
transient int size = 0;
transient Node<E> first; //整个链表的头结点
transient Node<E> last; //整个链表的尾结点
Node的数据结构如下 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; } }
如图所示
1构造器
有两个构造器,分别是空的和从一个集合创建。
注意:因为基于链表创建,理论上无容量的限制,不需要扩容的操作。
2 添加add(E e)
默认添加是在链表尾部添加
public boolean add(E e) { linkLast(e); return true; } 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++; }
3 获取get(int index)
public E get(int index) { checkElementIndex(index); return node(index).item; } 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; } } 注意:1跟arraylist不同的是,linkedlist查找指定下标元素需要遍历 2 >> 1 (除以2) <<1 (乘以2)
4 删除 remove(E e),remove(int index)
public boolean remove(Object o) { if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { //先溢出第一个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) { //当前元素是尾结点 last = prev; } else { next.prev = prev;//设置当前元素的前驱为后继的前驱 x.next = null; } x.item = null; //清空当前元素 size--; modCount++; return element; }
5 判断对象是否存在:contain(E e)
public boolean contains(Object o) { return indexOf(o) != -1; } public int indexOf(Object o) { int index = 0; if (o == null) { //从头开始找 找到第一个null for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { //从头开始找 看有没有等于item的 for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; }
总结:1 Jdk8中的linkedList基于双向链表来实现的,插入删除快,查询慢,适合读少写多的情况
2 linkedList还有一些有趣的方法,可以实现队列
3添加元素时不用扩容
4 线程不安全