第52章

Java Vector和Stack

深入学习Java中的Vector和Stack集合类:线程安全特性、常用方法、与现代集合的对比和实际应用场景

学习目标

Vector详解

什么是Vector?

Vector是Java早期提供的动态数组实现,类似于ArrayList,但具有线程安全特性。Vector中的所有方法都是同步的,这使得它在多线程环境中是安全的,但也带来了性能开销。

Vector基本使用

Vector基本操作示例
import java.util.Vector;
import java.util.Enumeration;

public class VectorExample {
    public static void main(String[] args) {
        // 创建Vector
        Vector<String> vector = new Vector<>();
        
        // 添加元素
        vector.add("Apple");
        vector.add("Banana");
        vector.add("Orange");
        vector.addElement("Grape"); // Vector特有方法
        
        System.out.println("Vector内容: " + vector);
        System.out.println("大小: " + vector.size());
        System.out.println("容量: " + vector.capacity());
        
        // 访问元素
        System.out.println("第一个元素: " + vector.firstElement());
        System.out.println("最后一个元素: " + vector.lastElement());
        System.out.println("索引1的元素: " + vector.elementAt(1));
        
        // 使用Enumeration遍历(传统方式)
        System.out.println("\n使用Enumeration遍历:");
        Enumeration<String> enumeration = vector.elements();
        while (enumeration.hasMoreElements()) {
            System.out.println(enumeration.nextElement());
        }
        
        // 使用增强for循环遍历
        System.out.println("\n使用增强for循环遍历:");
        for (String fruit : vector) {
            System.out.println(fruit);
        }
        
        // 删除元素
        vector.removeElement("Banana");
        vector.removeElementAt(0);
        System.out.println("\n删除后: " + vector);
    }
}

Stack详解

什么是Stack?

Stack是Java提供的栈数据结构实现,继承自Vector类。它遵循LIFO(后进先出)原则,提供了push、pop、peek等栈操作方法。虽然功能完整,但现在推荐使用Deque接口的实现类。

Stack基本使用

Stack基本操作示例
import java.util.Stack;
import java.util.EmptyStackException;

public class StackExample {
    public static void main(String[] args) {
        // 创建Stack
        Stack<Integer> stack = new Stack<>();
        
        // 压入元素(push)
        stack.push(10);
        stack.push(20);
        stack.push(30);
        stack.push(40);
        
        System.out.println("Stack内容: " + stack);
        System.out.println("栈顶元素: " + stack.peek());
        
        // 弹出元素(pop)
        System.out.println("\n弹出操作:");
        while (!stack.isEmpty()) {
            System.out.println("弹出: " + stack.pop());
            if (!stack.isEmpty()) {
                System.out.println("当前栈顶: " + stack.peek());
            }
        }
        
        // 演示空栈异常
        try {
            stack.pop(); // 空栈弹出会抛出异常
        } catch (EmptyStackException e) {
            System.out.println("\n空栈异常: " + e.getMessage());
        }
        
        // 栈的实际应用:括号匹配
        System.out.println("\n括号匹配测试:");
        System.out.println("\"()\" 匹配: " + isValidParentheses("()"));
        System.out.println("\"()[]{}\" 匹配: " + isValidParentheses("()[]{}"));
        System.out.println("\"([)]\" 匹配: " + isValidParentheses("([)]"));
    }
    
    // 使用栈检查括号匹配
    public static boolean isValidParentheses(String s) {
        Stack<Character> stack = new Stack<>();
        
        for (char c : s.toCharArray()) {
            if (c == '(' || c == '[' || c == '{') {
                stack.push(c);
            } else if (c == ')' || c == ']' || c == '}') {
                if (stack.isEmpty()) return false;
                
                char top = stack.pop();
                if ((c == ')' && top != '(') ||
                    (c == ']' && top != '[') ||
                    (c == '}' && top != '{')) {
                    return false;
                }
            }
        }
        
        return stack.isEmpty();
    }
}

Vector vs ArrayList对比

特性 Vector ArrayList
线程安全 ✅ 同步,线程安全 ❌ 非同步,线程不安全
性能 较慢(同步开销) 较快
扩容机制 默认扩容100%(翻倍) 扩容50%
引入版本 JDK 1.0 JDK 1.2
遍历方式 Iterator, Enumeration, for-each Iterator, for-each
推荐使用 不推荐(遗留类) 推荐

使用建议

在现代Java开发中,通常不推荐使用Vector。如果需要线程安全的List,建议使用:

  • Collections.synchronizedList(new ArrayList<>())
  • CopyOnWriteArrayList(读多写少场景)
  • 使用并发控制机制保护ArrayList

Stack vs Deque对比

传统Stack

  • 继承自Vector,线程安全
  • 提供push、pop、peek方法
  • 性能较差(同步开销)
  • 功能单一,只能栈操作
  • 不推荐在新项目中使用

现代Deque

  • 接口设计,多种实现
  • 支持双端操作
  • 性能更好
  • 功能更丰富
  • 推荐使用ArrayDeque或LinkedList

Deque替代Stack示例

使用Deque实现栈操作
import java.util.Deque;
import java.util.ArrayDeque;

public class DequeAsStack {
    public static void main(String[] args) {
        // 使用Deque作为栈
        Deque<String> stack = new ArrayDeque<>();
        
        // 栈操作
        stack.push("First");   // 等同于addFirst
        stack.push("Second");
        stack.push("Third");
        
        System.out.println("栈内容: " + stack);
        System.out.println("栈顶元素: " + stack.peek()); // 等同于peekFirst
        
        // 弹出所有元素
        while (!stack.isEmpty()) {
            System.out.println("弹出: " + stack.pop()); // 等同于removeFirst
        }
        
        // Deque的额外功能:双端操作
        Deque<Integer> deque = new ArrayDeque<>();
        
        // 从两端添加
        deque.addFirst(1);
        deque.addLast(2);
        deque.addFirst(0);
        deque.addLast(3);
        
        System.out.println("\nDeque内容: " + deque);
        
        // 从两端移除
        System.out.println("从前端移除: " + deque.removeFirst());
        System.out.println("从后端移除: " + deque.removeLast());
        System.out.println("剩余内容: " + deque);
    }
}

完整代码示例

综合示例:Vector和Stack的实际应用
import java.util.*;

/**
 * Vector和Stack综合示例
 * 演示传统集合类的使用和现代替代方案
 */
public class VectorStackDemo {
    public static void main(String[] args) {
        System.out.println("=== Vector示例 ===");
        vectorExample();
        
        System.out.println("\n=== Stack示例 ===");
        stackExample();
        
        System.out.println("\n=== 现代替代方案 ===");
        modernAlternatives();
    }
    
    /**
     * Vector使用示例
     */
    public static void vectorExample() {
        Vector<String> vector = new Vector<>();
        
        // 添加元素
        vector.add("Java");
        vector.add("Python");
        vector.add("JavaScript");
        
        // Vector特有方法
        System.out.println("容量: " + vector.capacity());
        System.out.println("大小: " + vector.size());
        
        // 线程安全测试(简单演示)
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                vector.add("Thread1-" + i);
            }
        });
        
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                vector.add("Thread2-" + i);
            }
        });
        
        t1.start();
        t2.start();
        
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("最终Vector大小: " + vector.size());
    }
    
    /**
     * Stack使用示例:表达式求值
     */
    public static void stackExample() {
        String expression = "3 + 4 * 2";
        System.out.println("表达式: " + expression);
        System.out.println("结果: " + evaluateExpression(expression));
    }
    
    /**
     * 简单的表达式求值(仅支持+和*)
     */
    public static int evaluateExpression(String expression) {
        Stack<Integer> numbers = new Stack<>();
        Stack<Character> operators = new Stack<>();
        
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            
            if (c == ' ') continue;
            
            if (Character.isDigit(c)) {
                numbers.push(c - '0');
            } else if (c == '+' || c == '*') {
                while (!operators.isEmpty() && 
                       precedence(operators.peek()) >= precedence(c)) {
                    int b = numbers.pop();
                    int a = numbers.pop();
                    char op = operators.pop();
                    numbers.push(calculate(a, b, op));
                }
                operators.push(c);
            }
        }
        
        while (!operators.isEmpty()) {
            int b = numbers.pop();
            int a = numbers.pop();
            char op = operators.pop();
            numbers.push(calculate(a, b, op));
        }
        
        return numbers.pop();
    }
    
    private static int precedence(char op) {
        return op == '*' ? 2 : 1;
    }
    
    private static int calculate(int a, int b, char op) {
        return op == '+' ? a + b : a * b;
    }
    
    /**
     * 现代替代方案示例
     */
    public static void modernAlternatives() {
        // 使用ArrayList + 同步包装器替代Vector
        List<String> syncList = Collections.synchronizedList(new ArrayList<>());
        syncList.add("Modern");
        syncList.add("Approach");
        System.out.println("同步List: " + syncList);
        
        // 使用ArrayDeque替代Stack
        Deque<Integer> modernStack = new ArrayDeque<>();
        modernStack.push(1);
        modernStack.push(2);
        modernStack.push(3);
        
        System.out.println("现代栈: " + modernStack);
        System.out.println("弹出: " + modernStack.pop());
        
        // CopyOnWriteArrayList用于读多写少场景
        List<String> cowList = new CopyOnWriteArrayList<>();
        cowList.add("Thread-Safe");
        cowList.add("Read-Optimized");
        System.out.println("CopyOnWrite List: " + cowList);
    }
}
💻 查看完整代码 - 在线IDE体验

最佳实践

Vector和Stack使用建议

推荐做法

  • 新项目中使用ArrayList + 同步机制
  • 使用ArrayDeque替代Stack
  • 读多写少场景考虑CopyOnWriteArrayList
  • 明确线程安全需求再选择集合
  • 性能敏感场景避免不必要的同步

避免做法

  • 在新项目中直接使用Vector
  • 不考虑性能就使用同步集合
  • 混用传统和现代集合API
  • 忽略集合的扩容机制影响
  • 在单线程环境使用同步集合

本章小结