JDK8集合类源码解析 - LinkedList

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 线程不安全

 

posted on 2017-06-28 18:11  一只小蜗牛12138  阅读(160)  评论(0编辑  收藏  举报

导航