LinkedList 源码分析 Jdk 1.8

340 阅读2分钟

添加元素源码

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
        // 头指针不为空 最后一个元素的next 指向 新元素
        l.next = newNode;
    size++;
    modCount++;
}

node数据结构


private static class Node<E> {
    // 存放的数据
    E item;
    Node<E> next; // 上一个元素
    Node<E> prev; // 下一个元素  新的元素永远是最后一个元素
	// 所以没有next =null, prev =last

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

查找元素

 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;
        }
    }   

数据结构图

图片.png

作为队列的性质

private void linkFirst(E e) 
{
        // 1、先保留头指针
        final Node<E> f = first;
		// 2、创建新节点  新元素的next -->f 新元素的上一个没有null
        final Node<E> newNode = new Node<>(null, e, f);
		// 3、头指针指向-新节点
        first = newNode;
        if (f == null)
		    //头指针不在  尾指针 和 头指针 都指向第一个元素
            last = newNode;
        else
		    // 当添加第2个元素的时候 头指针的上一个元素指向新元素
            f.prev = newNode;
		// 元素个数+1	
        size++;
        modCount++;
}

队列offer源码

Queue<String> q1 = new LinkedList<>();
// 其实就是调用了add();方法
q1.offer("aa");
q1.offer("bb");
q1.offer("cc");
//  判断队列中是否有元素
while (q1.peek() != null)
{
    System.out.println(q1.poll());
}

// 堆栈
Deque<String> list = new LinkedList();
  // 其实就是调用了linkFirst 方法
  list.push("1111");
  list.push("2222");
  list.push("3333");
  while (list.peek() !=null)
  {
       String fd = list.poll();
       System.out.println(fd);
  }

peek 源码

public E peek() 
{
    //其实就是 获取头指针 指向的元素
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}

poll源码

public E poll() 
{
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}

unlinkFirst 源码

private E unlinkFirst(Node<E> f) 
{
    // 出队源码 永远出first指针指向的第一个元素
    // assert f == first && f != null;
    final E element = f.item;
    final Node<E> next = f.next;
    f.item = null;
    f.next = null; // help GC
    // 把头指针指向 第一个元素的下个地址
    first = next;
    if (next == null)
        last = null;
    else
        // 因为已经出队了 出队元素指向上一个元素的指针=null Help GC
        next.prev = null;
        // 数量--1
    size--;
    // 修改次数+1
    modCount++;
    return element;
}

出队 入队 判断是否有元素 都有2个方法 方法的区分是啥?

在尾部添加元素 (add, offer): add()会在长度不够时抛出异常:IllegalStateException; offer()则不会,只返回false

查看头部元素 (element, peek),返回头部元素,但不改变队列 element()会在没元素时抛出异常:NoSuchElementException; peek()返回null;

删除头部元素 (remove, poll),返回头部元素,并且从队列中删除 remove()会在没元素时抛出异常:NoSuchElementException; poll()返回null;