Contents

Java 中 Arraylist和vector

1. 概述

在本教程中,我们将重点关注ArrayListVector之间的区别。它们都属于 Java Collections Framework 并实现了java.util.List接口。

但是,这些类在实现上存在显着差异。

2. 有什么不同?

作为快速入门,让我们介绍ArrayListVector的主要区别。**然后,我们将更详细地讨论一些要点:

  • 同步——这两者之间的第一个主要区别。Vector是同步的,而ArrayList不是。
  • 大小增长——两者之间的另一个区别是它们在达到容量时调整大小的方式。Vector的大小翻了一番。相比之下,ArrayList只增加了一半的长度
  • 迭代 ——Vector可以使用IteratorEnumeration遍历元素。**另一方面,ArrayList只能使用 Iterator
  • 性能——很大程度上是由于同步, 与ArrayList相比,Vector操作更慢
  • 框架 – 此外,ArrayList是 Collections 框架的一部分,在 JDK 1.2 中引入。同时,Vector 作为遗留类存在于早期版本的 Java 中。

3. Vector

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

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

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

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

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

让我们添加一些值:

vector.add("blogdemo");
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. 并发

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

public synchronized E get(int index)

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

但是,实际上,无论如何,这种操作级别的同步都需要与我们自己的复合操作同步覆盖。

所以相比之下,ArrayList采用了不同的方法。它的方法是不同步的,并且这种关注被分离到专门用于并发的类中。

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

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

5. 性能

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

要查看VectorArrayList操作之间的性能差异 ,让我们编写一个简单的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 以使用三个线程和 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长得多 。