Java ArrayList与Vector

2023/06/07

1. 概述

在本教程中,我们将重点介绍ArrayList和Vector类之间的区别。它们都属于Java Collection Framework并实现了java.util.List接口。

然而,这些类在它们的实现上有很大的不同。

2. 有什么不同?

作为快速入门,让我们介绍一下ArrayList和Vector的主要区别。然后,我们将更详细地讨论其中的一些要点:

  • 同步:这两者之间的第一个主要区别。Vector是同步的,而ArrayList不是
  • 大小增长:两者之间的另一个区别是它们在达到容量时调整大小的方式。Vector将其大小加倍。相比之下,ArrayList仅增加其长度的一半
  • 迭代:Vector可以使用Iterator和Enumeration来遍历元素。另一方面,ArrayList只能使用Iterator
  • 性能:主要是由于同步,与ArrayList相比,Vector操作速度较慢
  • 框架:另外,ArrayList是集合框架的一部分,是在JDK 1.2中引入的。同时,Vector作为遗留类存在于早期版本的Java中

3. Vector

由于我们已经有了关于ArrayList的扩展指南,因此我们不会在这里讨论它的API和功能。另一方面,我们将介绍有关Vector的一些核心细节。

简单地说,Vector是一个可调整大小的数组。它可以随着我们添加或删除元素而增长和缩小。

我们可以用典型的方式创建一个Vector:

Vector<String> vector = new Vector<>();

默认构造函数创建一个初始容量为10的空Vector。

让我们添加一些值:

vector.add("tuyucheng");
vector.add("Vector");
vector.add("example");

最后,让我们使用Iterator接口遍历这些值:

Iterator<String> iterator = vector.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    // ...
}

或者,我们可以使用Enumeration遍历Vector:

Enumeration e = vector.elements();
while(e.hasMoreElements()) {
    String element = e.nextElement();
    // ... 
}

现在,让我们更深入地探索它们的一些独特功能。

4. 并发

我们已经提到ArrayList和Vector在并发策略上是不同的,但让我们仔细看看。如果我们深入研究Vector的方法签名,我们会看到每个方法都有synchronized关键字:

public synchronized E get(int index)

简单地说,这意味着一次只有一个线程可以访问给定的Vector

不过,实际上,这种操作级同步无论如何都需要用我们自己的复合操作同步来覆盖

所以相比之下,ArrayList采取了不同的做法。它的方法不是同步的,并且该问题被分离到专门用于并发的类中。

例如,我们可以使用CopyOnWriteArrayListCollections.synchronizedList来获得与Vector类似的效果:

vector.get(1); // synchronized
Collections.synchronizedList(arrayList).get(1); // also synchronized

5. 性能

正如我们上面已经讨论过的,Vector是同步的,这会对性能产生直接影响

要查看Vector与ArrayList操作之间的性能差异,让我们编写一个简单的JMH基准测试

之前,我们已经了解了ArrayList操作的时间复杂度,因此我们仅添加Vector的测试用例。

首先,让我们测试get()方法:

@Benchmark
public Employee testGet(ArrayListBenchmark.MyState state) {
    return state.employeeList.get(state.employeeIndex);
}

@Benchmark
public Employee testVectorGet(ArrayListBenchmark.MyState state) {
    return state.employeeVector.get(state.employeeIndex);
}

我们将JMH配置为使用3个线程和10次预热迭代。

并且,让我们报告纳秒级别的每次操作的平均时间:

Benchmark                         Mode  Cnt   Score   Error  Units
ArrayListBenchmark.testGet        avgt   20   9.786 ± 1.358  ns/op
ArrayListBenchmark.testVectorGet  avgt   20  37.074 ± 3.469  ns/op

我们可以看到ArrayList#get的执行速度大约是Vector#get的三倍

现在,让我们比较一下contains()操作的结果:

@Benchmark
public boolean testContains(ArrayListBenchmark.MyState state) {
    return state.employeeList.contains(state.employee);
}

@Benchmark
public boolean testContainsVector(ArrayListBenchmark.MyState state) {
    return state.employeeVector.contains(state.employee);
}

并将结果打印出来:

Benchmark                              Mode  Cnt  Score   Error  Units
ArrayListBenchmark.testContains        avgt   20  8.665 ± 1.159  ns/op
ArrayListBenchmark.testContainsVector  avgt   20  36.513 ± 1.266  ns/op

正如我们所看到的,对于contains()操作,Vector的执行时间比ArrayList长得多。

6. 总结

在本文中,我们了解了Java中Vector和ArrayList类之间的区别。此外,我们还更详细地介绍了Vector功能。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章