Vector是线程安全但性能差的动态数组,所有方法加synchronized锁整个对象;Stack继承Vector但破坏封装性且已弃用,推荐ArrayDeque或ConcurrentLinkedDeque替代。

Vector 是线程安全但性能差的动态数组
Vector 在 Java 早期版本中设计为 ArrayList 的线程安全替代品,所有方法(如 add()、get()、remove())都加了 synchronized。这导致单线程下明显慢于 ArrayList,且无法通过外部同步块优化——因为锁粒度是整个对象。
现代代码中基本不推荐直接使用 Vector,除非要对接遗留系统或必须满足 Enumeration 接口(比如某些老版 JMX 或 RMI 场景)。替代方案更常见:
- 单线程:用
ArrayList+ 手动同步(如Collections.synchronizedList(new ArrayList())),可按需控制锁范围 - 高并发读多写少:用
CopyOnWriteArrayList - 需要强一致性写操作:考虑
ConcurrentLinkedQueue或分段锁结构
Vectorv = new Vector<>(); v.add("a"); // 同步方法,内部调用 this.notifyAll() v.addElement("b"); // 等价于 add(),历史遗留命名
Stack 继承自 Vector,但语义和设计都不合理
Stack 类继承自 Vector,并添加了 push()、pop()、peek() 等栈操作方法。问题在于:它暴露了父类全部的 Vector 方法(如 insertElementAt()、removeElementAt()),破坏了栈的 LIFO 封装性;同时仍保留 Vector 的同步开销,而实际栈操作通常需要更细粒度控制。
Java 官方文档已明确标注 Stack 是“deprecated for removal”,JDK 21 起标记为待移除。真正该用的是:
立即学习“Java免费学习笔记(深入)”;
-
ArrayDeque:非线程安全,但性能最优(数组+双指针,无扩容拷贝抖动),支持push()/pop()/peek() - 需要线程安全时:用
ConcurrentLinkedDeque(无界、lock-free)或包装ArrayDeque+ReentrantLock
// 不要这样写 Stackstack = new Stack<>(); stack.push(1); stack.pop(); // 应该这样写 Deque stack = new ArrayDeque<>(); stack.push(1); stack.pop();
Vector 和 Stack 的序列化行为容易引发兼容性问题
两者都实现了 Serializable,但序列化字段是 elementData(Object[])、elementCount(int)和 capacityIncrement(int)。其中 capacityIncrement 在 Vector 构造时可设为非零值,用于控制扩容步长;但 ArrayList 没有这个字段,且 ArrayDeque 根本不序列化内部数组——这意味着跨版本反序列化 Vector/Stack 对象时,若接收端 JDK 升级或改用其他集合,极易抛出 InvalidClassException 或数据错乱。
更隐蔽的问题是:Stack 的 toString() 输出格式依赖 Vector 的实现,会显示类似 [1, 2, 3] 的列表形式,而非栈顶在前的直观表示,调试时易误判状态。
- 避免在网络传输或持久化场景中直接序列化 Vector/Stack 实例
- 如必须存档,先转成
List或 JSON(如 Jackson 序列化new ArrayList(stack)) - 检查日志或监控输出是否误把 Stack 当作普通列表解析
从 Vector 切换到现代集合时要注意的边界行为
Vector 的一些行为与 ArrayList 不一致,容易在迁移时引入 bug:
-
Vector.size()返回当前元素个数,但Vector.capacity()返回内部数组长度——ArrayList没有 public 的 capacity 方法,得用反射或ArrayList.class.getDeclaredField("elementData")获取(不推荐) -
Vector.removeElement(Object)删除第一个匹配项并返回 boolean;而ArrayList.remove(Object)也返回 boolean,但ArrayList.remove(int)返回被删元素——注意重载歧义 -
Stack.search(Object)返回“从栈顶起第几个位置”(1-indexed),而ArrayList.indexOf()是从头开始找(0-indexed),且找不到返回 -1
最常踩的坑是:用 stack.search(x) == 1 判断栈顶是否为 x,结果在换成 ArrayDeque 后逻辑失效——因为后者根本不提供 search 方法,得手动 deque.peekFirst().equals(x)。










