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

fjs*_*jsj 661 java stack vector deprecated obsolete

为什么Java Vector被认为是遗留类,已过时或已弃用?

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

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

怎么样Stack,这是一个子类Vector,我应该怎么用,而不是它?

Jon*_*eet 641

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

通常,您希望同步整个操作序列.同步单个操作既不安全(Vector例如,如果你遍历a ,你仍然需要取出一个锁以避免其他人同时更改集合,这会导致ConcurrentModificationException迭代线程中的一个)但也会更慢(为什么一旦足够就反复取出锁?

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

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

至于一个Stack等价物 - 我会看Deque/ ArrayDeque开始.

  • "通常你想要同步整个操作序列." - 这就是重点!谢谢! (106认同)
  • @Samir:不,我不会试图预测未来. (25认同)
  • @Samir:它没有被正式弃用 - 只是ArrayList通常是首选. (16认同)
  • 在哪个版本的java Deprecated Vector(目前我使用的是Java7).但我从未将其视为已弃用?Bye the way nice解释...... + 1 (7认同)
  • 只是gr8.vector并没有被弃用它是一个遗留类.在deprecated和legacy之间必须有区别,是的,请参阅http://stackoverflow.com/questions/2873254/difference-between-a-deprecated-and-a-legacy-api (4认同)
  • @specializt:我认为在这个阶段我们必须同意不同意. (4认同)
  • @Jon 感谢您的解释。一个小修正 - “例如,如果您迭代 Vector,您仍然需要取出锁以避免其他人同时更改集合”这一说法仅部分正确 - 迭代器将抛出 ConcurrentModificationException 以避免如果发生这种情况,将出现不可预测的行为。 (2认同)
  • @Alex:嗯,我的观点是你要同步以避免另一个线程尝试这样做的后果.将澄清. (2认同)
  • @Alex:迭代器将*尝试*抛出异常.但是,这并不能保证.文档基本上说"这只是为了帮助检测错误.不要依赖它." (2认同)
  • 有没有我们真正需要使用Vector的情况? (2认同)
  • @Nenad:我真的无法回答这个问题 - 但如果我写这样一本书,那不是我要做的. (2认同)
  • 我一直不明白为什么有人仅仅因为效率低下就将某些 API 的某些部分称为“死”或“遗留”。NEWSFLASH:几乎所有的算法都可以优化,很多都是低效的——但没有人称之为“死”。效率不再重要,我们处于 21 世纪,因此除非您正在为航天飞机(好吧,继任者)编写高性能嵌入式软件,否则对这样的 API 大喊大叫是没有意义的——即使如此:*软件工程师*只是选择一些替代方案,他们不会咆哮,但现在不用担心:) (2认同)
  • @specializt:我认为将其称为遗留API是完全合理的,如果有一种替代方案在大多数情况下显然更好."Vector"不仅在不必要的同步方面效率较低,而且通过进行同步,它可以为不熟悉线程的用户提供线程安全的*错觉,并认为同步每个操作足以使其安全跨线程任意使用.几乎在所有情况下,我仍然非常乐意建议从"Vector"移动到"ArrayList". (2认同)
  • @specializt:不,我不这么认为.搜索"define:legacy",计算状态的相关形容词:"表示或与软件或硬件相关的已被取代但由于其广泛使用而难以替换".这听起来和我说的很相似.请注意,"在大多数情况下更好"是一个相当高的标准 - 而`LinkedList <T>`在*某些*情况下优于`ArrayList <T>`,反之通常是正确的 - 既没有有效地弃用另一个. (2认同)

Jus*_*tin 80

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

1.命名:向量实际上只是可以作为数组访问的列表,因此它应该被调用ArrayList(这是Java 1.2 Collections的替代品Vector).

2.并发性:所有的get(),set()方法是synchronized,所以你不能有超过同步进行细粒度控制.

ArrayList和之间没有太大区别Vector,但你应该使用ArrayList.

来自API文档.

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

  • @dhardy List以数组作为其底层实现.有`ArrayList`,`LinkedList`等,所有这些都实现了接口`List`,所以如果你想利用`List`方法而不必知道底层实现到底是什么,你可以只需要一个`List `作为方法的参数等.这同样适用于`Map`等的实现者.同时,C++确实有一个`std :: array`类,它只是C风格静态长度数组的基于模板的替代品. (6认同)

Yis*_*hai 41

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


Bri*_*enk 14

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

  • 正如Jon所说,Vector不会表现得那么好,而且这种方法可以让你选择何时进行同步.这完全是一个设计问题.您应该使用ArrayList over Vector,因为您应该默认使用非同步访问. (8认同)
  • 为什么这比矢量更好? (2认同)

200*_*ess 6

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

不过,它继承了很多东西.事实java.util.Stack extends java.util.Vector是面向对象设计中的错误.纯粹主义者会注意到它除了传统上与堆栈相关的操作之外还提供了许多方法(即:push,pop,peek,size).它也可以做到search,elementAt,setElementAt,remove,和其他许多随机存取操作.基本上由用户决定不使用非堆栈操作Stack.

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