LinkedList源码分析

LinkedList

概述

LinkedList是一个双向链表,每个节点持有next和prev的引用,该类实现了List和Deque接口。与ArrayList类似,这个容器也不是线程安全的,可以通过Collections.synchronizedList来转换。通过iterator获得的迭代器也是fail-fast的。

源码分析

  1. 构造器
    // 头结点
    transient Node<E> first;
    // 尾节点
    transient Node<E> last;
    // 创建空链表
    public LinkedList() {
    }
    // 创建链表,包含给定集合的所有元素
    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

first和last分别指向头和尾节点,构造函数中并没有做啥操作。
Node是链表的节点,封装了item,分别持有prev和next的引用,也没啥特别的。

```
2. add
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++;
}
add的操作其实就是普通的添加链表节点的操作,逻辑很简单。
3. remove
// 这个remove方法与ArrayList的基本类似,根据是否为null来处理,找到第一个对应元素就直接删除
public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
            // unlink就是删除链表节点的逻辑,常规的链表操作
                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;
}
remove也是比较简单,跟ArrayList的基本类似,学过数据结构的都很熟悉了。
这个类里还有unlinkLast和unlinkFirst方法,逻辑基本跟unlink类似,只是各少了一个分支而已。从代码的角度来看其实会显得有点多余,但这种基础类库效率是很重要的,所以即使代码丑一点也可以理解。。
4. getset
public E get(int index) {
    checkElementIndex(index);
    // node(index)是遍历链表的方法,从头结点或尾节点开始顺序遍历来查找
    return node(index).item;
}
public E set(int index, E element) {
    checkElementIndex(index);
    Node<E> x = node(index);
    E oldVal = x.item;
    x.item = element;
    return oldVal;
}

“`
get和set两个方法很直观,就是遍历找到节点来操作。这里一个小的优化点就是判断查找的索引是在前一半还是后一半,查找时就近从头结点或尾节点开始查找。

总结

LinkedList也是很简单的一个容器,知道底层是链表的结构,熟悉链表的操作即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值