为什么Java向量被认为是遗留的类,过时的或被弃用的?
使用并发时,它的使用是否有效?
如果我不想手动同步对象,只想使用线程安全集合而不需要对底层数组进行新的复制(如CopyOnWriteArrayList所做),那么使用Vector是否可以?
那么作为Vector的一个子类的Stack呢,我应该用什么来代替它呢?
Vector在每个单独操作上同步。这几乎不是你想做的。
通常,您希望同步整个操作序列。同步单个操作既不太安全(例如,如果您在Vector上进行迭代,您仍然需要取出一个锁,以避免其他人同时更改集合,这将导致迭代线程中出现ConcurrentModificationException),也会变慢(为什么在一次足够时重复取出一个锁)?
当然,它也有锁的开销,即使你不需要锁。
基本上,在大多数情况下,它是一种非常有缺陷的同步方法。正如Brian Henk先生指出的那样,您可以使用Collections.synchronizedList等调用来装饰一个集合——事实上,Vector将"调整大小的数组"集合实现与"同步每个操作"位结合在一起,这是糟糕设计的另一个例子;装饰方法提供了更清晰的关注分离。
至于Stack等价物,我先看Deque和ArrayDeque。
- "一般情况下,您希望同步整个操作序列。"—这就是重点!谢谢!
- 在哪种版本的Java表示向量(目前我使用Java7),但我从来没有看到一个弃权?再见,很好的解释…+1
- @萨米尔:这并不是官方反对的——只是普遍倾向于使用ArrayList。
- 你能告诉我,将来会发生这种事吗?
- @萨米尔:不,我不会去预测未来。
- @乔恩谢谢你的解释。一个微小的修正——例如,"如果你在一个向量上迭代,你仍然需要取出一个锁来避免其他人同时更改集合"的语句,只是部分正确——如果发生这种情况,迭代器将抛出一个ConcurrentModificationException来避免不可预知的行为。
- @亚历克斯:好吧,我的意思是你同步以避免另一个线程试图这样做的后果。将澄清。
- @亚历克斯:迭代器将尝试抛出异常。但这并不能保证。文档基本上说"这只是为了帮助检测错误。不要依赖它。"
- 好的(填充空间…)
- 简单地说GR8。vector不是弃用它的遗留类。弃用和遗留类之间必须有区别,是的,请参阅stackoverflow.com/questions/2873254/…
- 有没有我们实际需要使用向量的情况??
- @Rajaasthana:好吧,您可能正在与另一个使用它的API进行互操作。不过,我记不起上次用新代码看到它的时候了。
- 我确实看到了很多代码,特别是在添加错误时,比如errorvector.add("无效名称")。我们需要避免这个吗?
- @拉贾阿斯塔纳:那真的取决于上下文。你在哪里看到这些代码?它是否在某些遗留代码库中?
- 是的,它在旧代码库中。
- @拉贾阿斯塔纳:那就是你看到它的原因,基本上。
- @上一次我在代码中看到矢量是在Giulio Zambon的"Starting JSP,JSF and Tomcat"中的一些示例代码中。我正在看。现在,在读了你的帖子之后,我想知道他为什么还在使用它?特别是在他开始安装Java 7 SDK(和Tomcat 7)的书时。至于代码本身,他使用它是因为同步…
- @尼纳德:我真的不能回答这个问题——但如果我写这样一本书,我就不会这么做了。
- 向量有一个简短的诱人的名字和它的壕沟在C++中的优势,这是许多程序员开始的。除了(效率低下)与向量的内置同步之外,您应该能够对ArrayList执行任何可以对向量执行的操作,并且通常执行得更快。
- 我从来都不明白为什么有人仅仅因为某些API的效率低下而把它的某些部分称为"死的"或"遗留的"。新闻快讯:几乎所有的算法都可以优化,很多都是低效的-但没有人称它为"死"。效率不再重要了,我们正处于21世纪,所以除非你正在为航天飞机编写高性能的嵌入式软件(好吧,继任者),否则就没有必要对这种API大声疾呼——即使是这样:软件工程师只需选择一些替代方案,他们不会大声疾呼,但现在也不担心这一点:)
- @专家:我认为,如果有一个在大多数情况下明显更好的替代方案,那么称它为遗留API是完全合理的。Vector不仅在不必要的同步方面效率较低,而且通过进行同步,它可以给刚开始线程化的用户带来线程安全的错觉,并认为同步每个操作足以使其安全地跨线程任意使用。我仍然很高兴地建议在几乎所有的情况下从Vector转到ArrayList。
- 这没有任何意义——如果有更好的选择,称之为"遗产"是合理的?你可能想再考虑一下……根据这种推理,几乎所有现存的东西都是"遗产"
- @专业人员:不,我不这么认为。搜索"define:legacy",计算的相关形容词表示:"表示或与已被取代但由于其广泛使用而难以取代的软件或硬件相关。"这听起来与我所说的很相似。请注意,"在大多数情况下更好"是一个相当高的标准——而在某些情况下,LinkedList比ArrayList好,相反的情况往往是正确的——两者都没有有效地贬低另一个。
- @specialist:同样,从jls 9.6.4.6:"注释为@deprecated的程序元素是不鼓励程序员使用的元素,通常是因为它很危险,或者因为存在更好的替代方法。"(是的,我知道deprecated和legacy不是同一个词,但它们在这里通常是同义词。不是说Vector被正式否决了,请注意…就像Date和Calendar不是,但我也不想在新开发中使用它们。)
- …所以它也被弃用了,因为你不想使用它。光晕。
- @专家:我认为在这个阶段我们必须同意不同意。
- 对于并发问题,我们可以使用Java并发包。但是,我们可以编写以非线程安全方式访问集合的代码。
- @乔恩,谢谢你的回答。"对于一个Stack等价物,我先看Deque/ArrayDeque,Stack是否也有同步方法作为它的超类Vector呢?我们应该用适用于Deque/ArrayDeque的Collections.synchronizedList来代替Stack吗?
- @本:不管怎样,我希望Stack中的任何调用都能通过超类方法进行,但我必须检查以确保。
Vector是1.0的一部分——最初的实现有两个缺点:
1。命名:向量仅仅是可以作为数组访问的列表,因此它应该被称为EDCOX1×9(即Java 1.2集合替换EDCOX1×1)。
2。并发性:所有get()、set()方法都是synchronized方法,所以不能对同步进行细粒度控制。
ArrayList和Vector没有太大的区别,但是你应该使用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.
- 列出哪些可以作为数组访问?arraylist并不是一个很短或很吸引人的名字,这可能就是为什么在其他地方使用vector(例如stl)。
- @以数组作为底层实现的数据列表。有ArrayList和LinkedList等,它们都实现了接口List,所以如果你想使用List方法,而不必知道底层实现实际上是什么,你只需要把List作为方法的参数,等等,这同样适用于Map等的实现者。同时,C++确实有一个EDCOX1×20类,它只是一个基于模板的C型静态长度数组的替换。
除了已有的关于使用向量的答案之外,向量还有一组围绕枚举和元素检索的方法,它们不同于列表接口,开发者(尤其是那些在1.2之前学习Java的人)可以在代码中使用它们。尽管枚举速度更快,但它们不会检查集合是否在迭代过程中被修改,这可能会导致问题,并且考虑到可能会选择向量进行同步(通过多个线程的助理访问),这使得它成为一个特别有害的问题。这些方法的使用还将许多代码与向量耦合起来,这样就不容易用不同的列表实现替换它。
您可以使用java.util.Collection上的synchronizedCollection/list方法从非线程安全集合中获取线程安全集合。
- 为什么这比向量更好?
- 正如jon所提到的,vector的性能不会很好,这个方法允许您选择何时进行同步是一个好主意。这完全是一个设计问题。您应该使用arraylist over vector,因为您应该默认为非同步访问。
- 这是如何回答这个问题的?
java.util.Stack继承java.util.Vector的同步开销,这通常是不合理的。
不过,它继承的远不止这些。事实上,java.util.Stack extends java.util.Vector是面向对象设计中的一个错误。纯粹主义者会注意到,除了传统上与堆栈相关的操作(即:push、pop、peek、size),它还提供了许多方法。也可以进行search、elementAt、setElementAt、remove和许多其他随机访问操作。基本上由用户决定,不要使用Stack的非堆栈操作。
基于这些性能和OOP设计原因,JavaDoc for java.util.Stack建议将ArrayDeque作为自然替代品。(deque不仅仅是一个堆栈,但至少它仅限于操作两端,而不是提供对所有内容的随机访问。)