JDK8源码阅读笔记
切换暗/亮/自动模式 切换暗/亮/自动模式 切换暗/亮/自动模式 返回首页

List



有序集合(也称为sequence)。该接口的用户可以精确控制列表中每个元素的插入位置。用户可以通过其整数索引(列表中的位置)访问元素,并在列表中搜索元素。

与集合不同,列表通常允许重复的元素。更正式地说,列表通常允许成对的元素e1e2,它们满足e1.equals(e2),并且如果允许空值,它们通常允许多个空元素。有人希望通过在用户尝试插入重复元素时抛出运行时异常来实现禁止重复的列表,这也并非不可行,但我们希望这种用法很少见。

List接口在已熟知的Collection 接口的规定之外有一些额外的规定,在iteratoraddremoveequalshashCode方法上。为了方便起见,还包括其他继承方法的声明。

List接口提供了四种使用位置(索引)访问列表元素的方法。列表(如Java数组)是从零开始的。请注意,对于某些实现(例如,LinkedList类),这些操作可能在时间上与索引值成比例地执行。因此,如果调用者不知道实现,则遍历列表中的元素通常比对其进行索引更可取。

List接口提供了一个特殊的迭代器,称为ListIterator,除Iterator接口的常规操作外,它还允许元素插入和替换以及双向访问。它还提供了一种获取列表迭代器的方法,该列表迭代器从列表中的指定位置开始。

List接口提供了两种搜索指定对象的方法。从性能的角度来看,应谨慎使用这些方法。在许多实现中,它们将执行昂贵的线性搜索。

List接口提供了两种方法,可以有效地在列表中的任意点插入和删除多个元素。

注意:虽然允许列表包含自己作为元素,但建议格外小心:equalshashCode方法在这样的列表上不再有很好的定义。

一些列表实现对它们可能包含的元素有限制。例如,某些实现禁止使用null元素,而某些实现对其元素类型进行限制。尝试添加不合格的元素会引发未经检查的异常,通常为NullPointerExceptionClassCastException。尝试查询不合格元素的存在可能会引发异常,或者可能仅返回false。一些实现将表现出前一种行为,而某些将表现出后者。更一般地,尝试对不合格元素进行操作,该操作的完成不会导致将不合格元素插入列表中,这可能会导致异常或成功,具体取决于实现方式。此类异常在此接口的规范中标记为“可选”。

该接口是Java集合框架的成员。

1. int size();

返回此列表中的元素数。如果此列表包含多于 Integer.MAX_VALUE 个元素,则返回Integer.MAX_VALUE

2. boolean isEmpty();

当前列表不包含元素时返回 true

3. boolean contains(Object o);

如果当前列表包含指定的元素则返回 true

更准确的说,当且仅当列表中至少存在一个元素满足 (o == null ? e == null : o.equals(e) 时返回 true

如果指定的元素类型不匹配,则可以抛出 ClassCastException ,但这是可选操作,也可以不抛出异常。

如果指定的元素是空,且当前列表不允许空元素,则可以抛出 NullPointerException ,这也是可选操作。

4. Iterator<E> iterator();

以正确的顺序返回在此列表中的元素上的迭代器。

5. Object[] toArray();

以正确的顺序(从第一个元素到最后一个元素)返回一个包含此列表中所有元素的数组。

返回的数组将是“安全的”,因为此列表不保留对其的引用。 (换句话说,即使此列表由数组支持,此方法也必须分配一个新数组)。因此,调用者可以自由修改返回的数组。

此方法充当基于数组的API和基于集合的API之间的桥梁。

6. <T> T[] toArray(T[] a);

返回一个数组,该数组按正确的顺序包含此列表中的所有元素(从第一个元素到最后一个元素);返回数组的运行时类型是指定数组的运行时类型。如果列表适合指定的数组,则将其返回。否则,将使用指定数组的运行时类型和此列表的大小分配一个新数组。

如果列表适合指定的数组并有剩余空间(即数组中的元素多于列表),则数组中紧接列表末尾的元素将设置为null。 (如果调用者知道列表不包含任何null元素,则这对于确定列表的长度很有用。)

toArray()方法类似,此方法充当基于数组的API和基于集合的API之间的桥梁。此外,此方法允许对输出数组的运行时类型进行精确控制,并且在某些情况下可以用来节省分配成本。

假设x是一个已知仅包含字符串的列表。以下代码可用于将列表转储到新分配的String数组中:

String[] y = x.toArray(new String[0]);

请注意,toArray(new Object[0])在功能上与toArray()相同。

7. boolean add(E e);

将指定的元素追加到此列表的末尾(可选操作)。

支持此操作的列表可能会限制可以添加到此列表的元素。特别是,某些列表将拒绝添加空元素,而另一些列表将对可能添加的元素类型施加限制。列表类应在其文档中明确指定对可以添加哪些元素的所有限制。

8. boolean remove(Object o);

如果存在指定元素,则从列表中删除该元素的第一个匹配项(可选操作)。如果此列表不包含该元素,则它保持不变。更准确的说,删除满足(o==null ? get(i)==null : o.equals(get(i))) 条件的最小索引i的元素(如果存在这样的元素)。如果此列表包含指定的元素(或者等效地,如果此列表由于调用而更改),则返回true

9. boolean containsAll(Collection c);

如果此列表包含指定集合的所有元素,则返回true

按照指定集合的迭代器返回的顺序(可选操作),将指定集合中的所有元素追加到此列表的末尾。如果在操作进行过程中修改了指定的集合,则此操作的行为是不确定的。 (请注意,如果指定的集合是此列表,并且是非空的,则将发生这种情况。)

10. boolean addAll(Collection<? extends E> c);

按照指定集合的迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾(可选操作)。如果在操作进行过程中修改了指定的集合,则此操作的行为是不确定的。 (请注意,如果指定的集合是此列表,并且是非空的,则将发生这种情况。)

11. boolean addAll(int index, Collection<? extends E> c);

将指定集合中的所有元素插入此列表中的指定位置(可选操作)。将当前在该位置的元素(如果有)和任何后续元素右移(增加其索引)。新元素将按照指定集合的迭代器返回的顺序显示在此列表中。如果在操作进行过程中修改了指定的集合,则此操作的行为是不确定的。 (请注意,如果指定的集合是此列表,并且是非空的,则将发生这种情况。)

12. boolean removeAll(Collection c);

从此列表中删除指定集合中包含的所有其元素(可选操作)。

13. boolean retainAll(Collection c);

仅保留此列表中包含的指定集合中的元素(可选操作)。换句话说,从该列表中删除所有未包含在指定集合中的元素。

14. default void replaceAll(UnaryOperator<E> operator)

用指定运算符应用于该元素的结果替换此列表中的每个元素。操作时抛出的错误或运行时异常将中继给调用方。

对于此list,默认实现等效于:

final ListIterator<E> li = list.listIterator();
while (li.hasNext()) {
		li.set(operator.apply(li.next()));
}

如果列表的列表迭代器不支持set操作,则替换第一个元素时将引发UnsupportedOperationException

源码如下:

default void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final ListIterator<E> li = this.listIterator();
		// 使用迭代器遍历当前集合
    while (li.hasNext()) {
        // 对遍历到的每个元素执行指定的操作,将得到的返回值替换当前元素
        li.set(operator.apply(li.next()));
    }
}

15. default void sort(Comparator<? super E> c)

根据指定的Comparator 所指定的顺序对该列表进行排序。

此列表中的所有元素必须相互可比,即使用指定的比较器(c.compare(e1, e2))不得为任何元素例如列表中的e1e2抛出ClassCastException

如果指定的比较器为null,则此列表中的所有元素都必须实现Comparable接口,并且应使用元素的Comparable自然排序。

该列表必须是可修改的,但无需可调整大小。

默认实现获取一个包含此列表中所有元素的数组,然后对该数组进行排序,并在此列表上进行迭代,从数组中的相应位置重置每个元素。(这避免了由于尝试对链表进行排序而导致的$n^2$ log(n)的性能开销。)

此实现是一种稳定的,自适应的,可迭代的合并排序,当对输入数组进行部分排序时,所需的比较少于n lg(n),而在对输入数组进行随机排序时,它提供了传统合并排序的性能。如果输入数组几乎已排序,则该实现需要大约n个比较。临时存储要求从几乎排序的输入数组的小常数到随机排序的输入数组的n/2对象引用,不一而足。

该实现在其输入数组中利用了升序和降序的同等优势,并且可以在同一输入数组的不同部分中利用了升序和降序的优势。它非常适合合并两个或多个排序后的数组:简单地将数组连接起来并对排序后的数组进行排序。

该实现改编自Tim Peters针对Python的列表排序TimSort。它使用了Peter McIlroy的“乐观排序和信息理论复杂性”技术,该技术在1993年1月举行的第四届ACM-SIAM离散算法年会上发表,第467-474页。

源码如下:

default void sort(Comparator<? super E> c) {
    // 将当前列表转换为数组a
    Object[] a = this.toArray();
    // 使用指定的比较器c对数组a进行排序
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
		// 遍历数组a,将每个元素放入当前集合
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

16. void clear();

从此列表中删除所有元素(可选操作)。此调用返回后,该列表将为空。

17. boolean equals(Object o);

比较指定对象与此列表是否相等。当且仅当指定对象也是一个列表,并且两个列表具有相同的大小,并且两个列表中所有对应的元素对都相等时(如果(e1==null ? e2==null : e1.equals(e2))),才返回true

换句话说,如果两个列表包含相同顺序的相同元素,则将两个列表定义为相等。此定义确保equals方法可在List接口的不同实现中正常工作。

18. int hashCode();

返回此列表的哈希码值。列表的哈希码定义为以下计算的结果:

int hashCode = 1;
for (E e : list)
		hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());

这样可以确保list1.equals(list2)意味着对于任意两个列表list1list2均有list1.hashCode()==list2.hashCode(),这是ObjecthashCode的基本要求。

19. E get(int index);

返回列表中指定位置的元素。

20. E set(int index, E element);

替换列表中指定位置的元素为指定的元素(可选操作),然后将返回被替换掉的元素。

21. void add(int index, E element);

将指定的元素插入此列表中的指定位置(可选操作)。将当前在该位置的元素(如果有)和任何后续元素右移(将其索引加一)。

22. E remove(int index);

删除此列表中指定位置的元素(可选操作)。将所有后续元素向左移动(将其索引减一)。然后返回从列表中删除的元素。

23. int indexOf(Object o);

返回指定元素在此列表中首次出现的索引;如果此列表不包含该元素,则返回-1。更准确地说,返回满足(o==null ? get(i)==null : o.equals(get(i)))的最小索引i或-1(如果没有这样的索引)。

24. int lastIndexOf(Object o);

返回指定元素在此列表中最后一次出现的索引;如果此列表不包含该元素,则返回-1。更准确地说,返回满足(o==null ? get(i)==null : o.equals(get(i)))的最大索引i或-1(如果没有这样的索引)。

25. ListIterator<E> listIterator();

返回此列表中的元素的列表迭代器(按适当顺序)。

26. ListIterator<E> listIterator(int index);

返回在此列表从指定位置开始的列表迭代器(以适当的顺序)。指定的索引就是初始调用next将返回的第一个元素。初次调用previous将返回指定索引减一的元素。

27. List<E> subList(int fromIndex, int toIndex);

返回此列表在指定的fromIndex(含)和toIndex(不含)之间的视图。 (如果fromIndextoIndex相等,则返回列表为空。)返回的列表由此列表支持,因此该列表中反映了返回列表中的非结构性更改 ,反之亦然。返回的列表支持此列表支持的所有可选列表操作。

此方法消除了对显式范围操作(数组通常存在的那种范围)的需要。通过subList视图而不是整个列表,可以对列表进行期望的任何范围操作。例如,以下常见用法从列表中删除了一系列元素:

list.subList(from, to).clear();

可以为indexOflastIndexOf构建类似的习惯用法,并且Collections类中的所有语法都可以应用于子列表。

如果后备列表(即此列表)以除通过返回列表以外的任何其他方式进行结构修改,则此方法返回的列表的语义将变得不确定。(结构修改是指更改此列表大小或以其他方式干扰列表的方式,正在进行的迭代可能会产生不正确的结果。)

28. default Spliterator<E> spliterator()

创建一个包含此列表所有元素的 Spliterator

Spliterator报告SIZEDORDERED。实现类应记录其他特征值的报告。

默认实现从列表的Iterator创建一个延迟绑定的拆分器。该拆分器继承了列表迭代器“快速失败”的属性。

创建的Spliterator还报告SUBSIZED

源码如下:

@Override
default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, Spliterator.ORDERED);
}