Java ArrayList 简介
1. 概述
在本文中,我们将了解 Java 集合框架中的ArrayList类。我们将讨论它的属性、常见用例以及它的优缺点。 ArrayList位于 Java 核心库中,因此您不需要任何其他库。为了使用它,只需添加以下导入语句:
import java.util.ArrayList;
List表示一个有序的值序列,其中某个值可能出现多次。
ArrayList是构建在数组之上的List实现之一,它能够在您添加/删除元素时动态增长和缩小。元素可以通过从零开始的索引轻松访问。此实现具有以下属性:
- 随机访问需要*O(1)*时间
- 添加元素需要摊销的常数时间O(1)
- 插入/删除需要*O(n)*时间
- 搜索未排序数组需要O(n)时间,排序数组需要O(log n)
2. 创建一个ArrayList
ArrayList有几个构造函数,我们将在本节中介绍它们。
首先,请注意ArrayList是一个泛型类,因此您可以使用所需的任何类型对其进行参数化,并且编译器将确保,例如,您将无法将Integer值放入Strings集合中。此外,从集合中检索元素时,您不需要强制转换元素。
其次,将泛型接口List用作变量类型是一种很好的做法,因为它将它与特定实现分离。
2.1.默认无参数构造函数
List<String> list = new ArrayList<>();
assertTrue(list.isEmpty());
我们只是创建一个空的ArrayList实例。
2.2. 构造函数接受初始容量
List<String> list = new ArrayList<>(20);
在这里,您指定底层数组的初始长度。这可以帮助您在添加新项目时避免不必要的调整大小。
2.3. 构造函数接受Collection
Collection<Integer> number
= IntStream.range(0, 10).boxed().collect(toSet());
List<Integer> list = new ArrayList<>(numbers);
assertEquals(10, list.size());
assertTrue(numbers.containsAll(list));
请注意,Collection实例的该元素用于填充底层数组。
3. 将元素添加到ArrayList
您可以在末尾或特定位置插入元素:
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(2L);
list.add(1, 3L);
assertThat(Arrays.asList(1L, 3L, 2L), equalTo(list));
您也可以一次插入一个集合或多个元素:
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"));
如果你想找到所有满足一个谓词的元素,你可以使用 Java 8 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()*方法执行删除。此方法的重载版本,它接受一个对象,搜索它并删除第一次出现的相等元素:
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();
}
}