为什么Java Vector(和Stack)类被认为已过时或已弃用?

Why is Java Vector (and Stack) class considered obsolete or deprecated?

为什么Java向量被认为是遗留的类,过时的或被弃用的?

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

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

那么作为Vector的一个子类的Stack呢,我应该用什么来代替它呢?


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

通常,您希望同步整个操作序列。同步单个操作既不太安全(例如,如果您在Vector上进行迭代,您仍然需要取出一个锁,以避免其他人同时更改集合,这将导致迭代线程中出现ConcurrentModificationException),也会变慢(为什么在一次足够时重复取出一个锁)?

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

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

至于Stack等价物,我先看DequeArrayDeque


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

1。命名:向量仅仅是可以作为数组访问的列表,因此它应该被称为EDCOX1×9(即Java 1.2集合替换EDCOX1×1)。

2。并发性:所有get()set()方法都是synchronized方法,所以不能对同步进行细粒度控制。

ArrayListVector没有太大的区别,但是你应该使用ArrayList

来自API文件。

As of the Java 2 platform v1.2, this
class was retrofitted to implement the
List interface, making it a member of
the Java Collections Framework. Unlike
the new collection implementations,
Vector is synchronized.


除了已有的关于使用向量的答案之外,向量还有一组围绕枚举和元素检索的方法,它们不同于列表接口,开发者(尤其是那些在1.2之前学习Java的人)可以在代码中使用它们。尽管枚举速度更快,但它们不会检查集合是否在迭代过程中被修改,这可能会导致问题,并且考虑到可能会选择向量进行同步(通过多个线程的助理访问),这使得它成为一个特别有害的问题。这些方法的使用还将许多代码与向量耦合起来,这样就不容易用不同的列表实现替换它。


您可以使用java.util.Collection上的synchronizedCollection/list方法从非线程安全集合中获取线程安全集合。


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

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

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