java.util.LinkedList学习笔记

概述


继承结构


类描述


如继承结构所示,LinkedList是两个接口(List和Deque)的混合实现。其实现了List接口中所有的可选操作,并且LinkedList允许所有元素(包括null)的插入和访问操作。LinkedList的所有操作均基于双向链表实现,当根据下标对链表中的元素进行访问,将通过从头至尾或者从尾至头遍历链表中的所有元素,来到达指定位置。

LinkedList和ArrayList都不是线程安全的。当多个线程同时访问一个链表时,如果有一个对链表的结构进行了修改,则必须在外部显示的进行同步的处理。一般情况下,通过对包含本链表的对象进行同步处理。如果没有这种类型的对象,则可以通过如下方式生成一个线程安全的链表:

List list = Collections.synchronizedList(new LinkedList(...));

该类中的iteratorlistIterator返回的迭代器仍然采用快速失败(fail-fast)机制:当链表由于调用除该迭代器的removeadd方法外,产生了结构行修改,该迭代器将抛出一个同步修改异常(ConcurrentModificationException)。因此,当发生同步修改时,迭代器将不会在未来的某个时间里,返回潜在的脏数组,或者产生不可预期的行为。

注意:快速失败机制并不会保证方法生非同步并发修改时行为的正确性(我想到的情况是:在两个进程进行列表结构修改操作的时间相同,且对方法中进行失败机制校验的方法调用时间也极其接近时,可能出现两个进程均通过同步修改校验, 且均对链表进行了结构行修改),这样对于这两个进程,仍然认为链表的是同步的,其实已经产生了脏数据。快速失败机制只是在保证检测到同步修改时,抛出异常,证明脏数据存在的可能。因此,在编码过程中最好不要依赖同步修改异常做逻辑处理,但快速失败机制一般可用于调试bug。

内部类介绍


数据节点类(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;
    }
}
类说明

Node类为一个静态内部类,其不需要外部对象即可初始化。由Node的结构及属性可以看出,LinkedList的数据存储结构与C
语言中双向链表形式相同。每个节点除持有该节点的有效数据外,还需要持有指向上个节点和下个节点的指针,因此其单个节点占用的空间高于ArrayList中采用数组存储的节点。

列表迭代器类(ListItr)


属性介绍

private Node<E> lastReturned;

用户最后一次调用next()或者previous返回的节点;

private Node<E> next;

用户下次调用next()返回的节点;

private int nextIndex;

用户下次调用next()返回的节点的下标值。

private int expectedModCount = modCount;

迭代器创建时,其持有的链表对象发生结构性修改的次数,主要用于并发修改的校验;


构造方法

ListItr(int index) {
    // assert isPositionIndex(index);
    next = (index == size) ? null : node(index);
    nextIndex = index;
}

生成一个由链表特定位置开始的列表迭代器。当用户传入的index(有效下标为0 ~ size-1)与链表长度size相等时,则代表调用next()方法时,将不会返回任何有效元素(抛出异常或者返回null)。


方法介绍

public boolean hasNext() {
    return nextIndex < size;
}

判断链表迭代器下次调用next方法时,是否还能返回有效的元素。由于链表中元素的有效下标范围时0 ~ size-1,因此当迭代器游标位置小于链表长度size时,则返回true,否则返回false。

public E next() {
    checkForComodification();
    if (!hasNext())
        throw new NoSuchElementException();

    lastReturned = next;
    next = next.next;
    nextIndex++;
    return lastReturned.item;
}

返回列表迭代器当前游标对应的元素。在进行元素访问之前,需要进行并发修改的校验。由代码可以看出,LinkedList迭代器的原生迭代器抛出异常来代表链表中不再有有效元素,而不是返回一个特殊值(null)。

public boolean hasPrevious() {
    return nextIndex > 0;
}

判断列表迭代器下次调用previous时,是否还能返回有效的元素。当列表迭代器的游标大于0时,则代表列表迭代器可以向前遍历,返回true,否则返回false。

public E previous() {
    checkForComodification();
    if (!hasPrevious())
        throw new NoSuchElementException();

    lastReturned = next = (next == null) ? last : next.prev;
    nextIndex--;
    return lastReturned.item;
}

返回迭代器当前游标的前一个元素。注意,在调用本方法时,当迭代器位于链表的尾端时,需要特殊处理。因为迭代器位于链表尾端时,迭代器中的的next对应的节点为null。

public int nextIndex() {
    return nextIndex;
}

返回链表下次调用next()方法返回元素的下标,与nextIndex相等。

public int previousIndex() {
    
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值