ChatGPT解决这个技术问题 Extra ChatGPT

为什么 Java Vector(和 Stack)类被认为已过时或不推荐使用?

为什么 Java Vector 被视为遗留类、已过时或已弃用?

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

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

StackVector 的子类,我应该用什么来代替它?

它们已过时,但并未弃用。

A
Am_I_Helpful

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

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

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

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

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


“通常,您希望同步整个操作序列。” - 这就是我想说的!谢谢!
在哪个版本的 java Deprecated Vector 中(目前我使用的是 Java7)。但我从未将其视为已弃用?再见很好的解释...+1
@Samir:它没有被正式弃用 - 只是 ArrayList 通常是首选。
@Samir:不,我不会试图预测未来。
@specializt:我认为在这个阶段我们必须同意不同意。
r
roottraveller

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

<强> 1。命名: 向量实际上只是可以作为数组访问的列表,所以它应该被称为 ArrayList(它是 Vector 的 Java 1.2 Collections 替代品)。

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

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

来自 API 文档。

从 Java 2 平台 v1.2 开始,该类被改进为实现 List 接口,使其成为 Java Collections Framework 的成员。与新的集合实现不同,Vector 是同步的。


可以作为数组访问的列表? ArrayList 不是一个很短或很吸引人的名称,这可能就是为什么在其他地方(例如 STL)使用 vector 的原因。
@dhardy 以数组作为其底层实现的列表。有 ArrayListLinkedList 等,它们都实现了接口 List,所以如果您想使用 List 方法而不必知道底层实现实际上是什么,您只需使用 {3 } 作为方法等的参数。这同样适用于 Map 等的实现者。同时,C++ 确实有一个 std::array 类,它只是 C 样式静态长度数组的基于模板的替代品。
Y
Yishai

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


N
Nubok

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


为什么这比矢量好?
正如 Jon 所提到的,Vector 的性能不会那么好,并且此方法允许您选择何时进行同步是个好主意。它完全是一个设计问题。您应该使用 ArrayList 而不是 Vector,因为您应该默认使用非同步访问。
这如何回答这个问题?
2
200_success

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 作为自然替代品。 (双端队列不仅仅是一个堆栈,但至少它仅限于操作两端,而不是提供对所有内容的随机访问。)