为什么JavaVector(和Stack)类被视为过时或不建议使用?

为什么JavaVector被认为是遗留类,过时或不建议使用?

在使用并发时,它的使用是否有效?

如果我不想手动同步对象,只想使用线程安全的集合,而不需要制作底层数组的新副本(如CopyOnWriteArrayList所做),那么使用Vector可以吗?

关于Stack,它是Vector的子类,我应该使用什么来代替它?

237876 次浏览

您可以使用java.util.Collection中的同步收集/列表方法从非线程安全的集合中获取线程安全的集合。

Vector在每个单独的操作上同步。这几乎不是你想做的。

通常你想同步整个序列的操作。同步单个操作既不太安全(例如,如果你迭代Vector,你仍然需要取出一个锁来避免其他人同时更改集合,这将导致迭代线程中的ConcurrentModificationException),但也更慢(为什么一次就足够了,为什么要重复取出锁?

当然,它也有锁定的开销,即使你不需要。

基本上,在大多数情况下,这是一种非常有缺陷的同步方法。正如Brian Henk先生指出的,您可以使用Collections.synchronizedList等调用装饰集合-Vector将“调整大小的数组”集合实现与“同步每个操作”位相结合的事实是另一个设计不佳的例子;装饰方法提供了更清晰的关注点分离。

至于Stack等价物——我会先看看Deque/ArrayDeque

Vector是1.0的一部分——原始实现有两个缺点:

1.命名:向量实际上只是可以作为数组访问的列表,因此它应该被称为ArrayList(这是Vector的Java1.2集合替换)。

2.并发:所有get()set()方法都是synchronized,因此您无法对同步进行细粒度控制。

ArrayListVector之间没有太大区别,但您应该使用ArrayList

从API文档。

从Java2平台v1.2开始,这个 类被改造以实现 列表接口,使其成为 Java集合框架 新的集合实现, 向量已同步。

除了已经声明的关于使用Vector的答案之外,Vector还有一系列围绕枚举和元素检索的方法,这些方法与List接口不同,开发人员(尤其是那些在1.2之前学习Java的开发人员)可以倾向于在代码中使用它们。尽管枚举更快,但它们不会检查集合在迭代中是否被修改,这可能会导致问题,并且考虑到Vector可能被选择用于其同步化——随之而来的来自多线程的访问,这使得它成为一个特别有害的问题。这些方法的使用也将大量代码耦合到Vector,因此不容易用不同的List实现替换它。

java.util.Stack继承了java.util.Vector的同步开销,这通常是不合理的。

然而,它继承了更多。java.util.Stack extends java.util.Vector是面向对象设计中的一个错误这一事实。纯粹主义者会注意到,除了传统上与堆栈相关的操作(即:press、pop、peek、size)之外,它还提供了许多方法。还可以执行searchelementAtsetElementAtremove和许多其他随机访问操作。基本上由用户避免使用Stack的非堆栈操作。

出于这些性能和OOP设计的原因,java.util.Stack的JavaDoc推荐ArrayDeque作为自然替代品。(双端队列不仅仅是一个堆栈,但至少它仅限于操作两端,而不是提供对所有内容的随机访问。)