Java ArrayList 介绍

1. 概述

在本文中,我们将从 Java Collections Framework 中了解 ArrayList 类。介绍它的属性、常用用法。

ArrayList 是在 Java 核心库中实现的,因此不需要依赖任何其他库。只需添加以下import语句就可使用:

import java.util.ArrayList;

List 表示值的有序序列,其中某些值可能出现多次。

ArrayList 是在数组之上构建的列表实现之一,它能够在您添加/删除元素时动态增长和收缩,元素可以通过从零开始的索引轻松访问。此实现具有以下属性:

  • 随机访问时间复杂度为O1)
  • 添加元素时间复杂度 为O1)
  • 插入/删除时间复杂度为O(n)
  • 搜索未排序的数组的时间复杂度 为O(n) ,排序数组时间复杂度为 O(log n)

2. 创建ArrayList

ArrayList 有几个构造函数,我们将在本节中介绍它们。

首先,请注意 ArrayList 是一个泛型类,因此您可以使用所需的任何类型对其进行参数化,编译器确保所赋值的类型的正确性,例如,无法将 Integer类型的值放入String集合中。此外,从集合中检索元素时,无需强制转换元素。

其次,最好将泛型接口 List 用作变量类型,因为它将其与特定实现分离。

2.1. 默认的无参数构造函数

List<String> list = new ArrayList<>();
assertTrue(list.isEmpty());

我们只是创建一个空的 ArrayList 实例。

2.2. 构造函数接受初始容量

List<String> list = new ArrayList<>(20);

在这里指定基础数组的初始长度。这有助于避免在添加新项目时不必要地调整大小。

2.3. 构造函数接受集合

Collection<Integer> numbers 
  = IntStream.range(0, 10).boxed().collect(toSet());

List<Integer> list = new ArrayList<>(numbers);
assertEquals(10, list.size());
assertTrue(numbers.containsAll(list));

请注意,集合实例的该元素用于填充基础数组。

3. 将元素添加到ArrayList

List<Long> list = new ArrayList<>(Arrays.asList(1L, 2L, 3L));
LongStream.range(4, 10).boxed()
  .collect(collectingAndThen(toCollection(ArrayList::new), ys -> list.addAll(0, ys)));
assertThat(Arrays.asList(4L, 5L, 6L, 7L, 8L, 9L, 1L, 2L, 3L), equalTo(list));

4. 遍历ArrayList

有两种类型的迭代器可用:Iterator和ListIterator

前者可以在一个方向上遍历列表,而后者允许你在两个方向上遍历列表。

以下仅向展示ListIterator

List<Integer> list = new ArrayList<>(
  IntStream.range(0, 10).boxed().collect(toCollection(ArrayList::new))
);
ListIterator<Integer> it = list.listIterator(list.size());
List<Integer> result = new ArrayList<>(list.size());
while (it.hasPrevious()) {
    result.add(it.previous());
}

Collections.reverse(list);
assertThat(result, equalTo(list));

还可以使用迭代器搜索、添加或删除元素。

5. 搜索ArrayList

List<String> list = LongStream.range(0, 16)
  .boxed()
  .map(Long::toHexString)
  .collect(toCollection(ArrayList::new));
List<String> stringsToSearch = new ArrayList<>(list);
stringsToSearch.addAll(list);

5.1. 搜索未排序列表

为了找到一个元素,可以使用indexOf() lastIndexOf()方法。它们都接受一个对象并返回 int 值:

assertEquals(10, stringsToSearch.indexOf("a"));
assertEquals(26, stringsToSearch.lastIndexOf("a"));Copy

如果要查找满足条件的所有元素,可以使用 Stream API使用Predicate过滤集合,如下所示:

Set<String> matchingStrings = new HashSet<>(Arrays.asList("a", "c", "9"));

List<String> result = stringsToSearch
  .stream()
  .filter(matchingStrings::contains)
  .collect(toCollection(ArrayList::new));

assertEquals(6, result.size());

也可以使用 for 循环或迭代器:

Iterator<String> it = stringsToSearch.iterator();
Set<String> matchingStrings = new HashSet<>(Arrays.asList("a", "c", "9"));

List<String> result = new ArrayList<>();
while (it.hasNext()) {
    String s = it.next();
    if (matchingStrings.contains(s)) {
        result.add(s);
    }
}

5.2. 搜索排序列表

如果你有一个顺序数组,那么你可以使用比线性搜索更快的二叉搜索算法:

List<String> copy = new ArrayList<>(stringsToSearch);
Collections.sort(copy);
int index = Collections.binarySearch(copy, "f");
assertThat(index, not(equalTo(-1)));

请注意,如果未找到元素,则将返回 -1。

6. 在ArrayList中删除元素

为了删除一个元素,应该找到它的索引,然后才通过remove()方法执行删除。此方法的重载版本,它接受对象,搜索它并删除和传入对象相等(equal)的第一个匹配项:

List<Integer> list = new ArrayList<>(
  IntStream.range(0, 10).boxed().collect(toCollection(ArrayList::new))
);
Collections.reverse(list);

list.remove(0);
assertThat(list.get(0), equalTo(8));

list.remove(Integer.valueOf(0));
assertFalse(list.contains(0));

但在使用装箱类型(如Integer)时要小心。为了删除特定元素,您应该首先将 int 值装箱处理,否则,以此值为索引的元素将被删除。

您也可以使用上述 Stream API 来删除多个元素,此处不做代码演示。我们也可以通过一个迭代器删除多个元素:

Set<String> matchingStrings
 = HashSet<>(Arrays.asList("a", "b", "c", "d", "e", "f"));

Iterator<String> it = stringsToSearch.iterator();
while (it.hasNext()) {
    if (matchingStrings.contains(it.next())) {
        it.remove();
    }
}

7. 总结

本中文我们简单整理了一下 Java 中的 ArrayList。

展示了如何创建 ArrayList 实例,如何使用不同的方法添加、查找或删除元素。

GitHub 上找到所有代码示例。

原文:https://www.baeldung.com/java-arraylist