Stack 是 Java 中基于栈数据结构实现的集合类,核心特性是后进先出(LIFO, Last In First Out),也就是最后放入的元素最先被取出。

它继承自 Vector,是线程安全的集合,常用于方法调用栈、表达式求值、括号匹配、撤销操作等场景。

1.Stack 核心方法

Stack 提供了 5 个专用方法,完全满足栈的操作需求:

方法作用
push(E item)入栈:将元素压入栈顶
pop()出栈:移除并返回栈顶元素(栈空会抛异常)
peek()查看栈顶:返回栈顶元素但不移除(栈空会抛异常)
empty()判空:栈为空返回 true,否则 false
search(Object o)查找元素:返回元素距栈顶的位置(栈顶 = 1,找不到返回 - 1)

2.基础使用实例

import java.util.Stack;

public class StackDemo {
    public static void main(String[] args) {
        // 1. 创建栈对象(存储字符串类型)
        Stack<String> stack = new Stack<>();

        // 2. push:元素入栈
        stack.push("Java");
        stack.push("Python");
        stack.push("C++");
        System.out.println("入栈后:" + stack); // [Java, Python, C++]

        // 3. peek:查看栈顶元素(不删除)
        System.out.println("栈顶元素:" + stack.peek()); // C++

        // 4. pop:出栈(删除并返回栈顶)
        String top = stack.pop();
        System.out.println("出栈元素:" + top); // C++
        System.out.println("出栈后:" + stack); // [Java, Python]

        // 5. empty:判断栈是否为空
        System.out.println("栈是否为空:" + stack.empty()); // false

        // 6. search:查找元素位置(栈顶=1)
        System.out.println("Java 位置:" + stack.search("Java")); // 2
        System.out.println("Go 位置:" + stack.search("Go")); // -1(不存在)
    }
}

运行结果

入栈后:[Java, Python, C++]
栈顶元素:C++
出栈元素:C++
出栈后:[Java, Python]
栈是否为空:false
Java 位置:2
Go 位置:-1

3.关键注意事项

1.栈空操作会抛异常
调用 pop()/peek() 时,如果栈为空,会抛出 EmptyStackException建议先判空

if (!stack.empty()) {
    stack.pop();
}

2.线程安全但效率低

Stack 继承自 Vector,所有方法都加了 synchronized 锁,线程安全但性能较差。➡️ 推荐替代方案:单线程用 ArrayDeque,双端队列性能远超 Stack。

3.继承设计不推荐

Java 官方不推荐使用 java.util.Stack,更推荐用 Deque 接口实现栈:

// 官方推荐的栈写法(性能更好)
Deque<String> stack = new ArrayDeque<>();

4.源码

1.push(入栈)

逻辑:元素添加到数组最后一位(栈顶)

public E push(E item) {
    addElement(item); // 调用 Vector 的方法,尾部追加元素
    return item;
}
// Vector.addElement 底层:
// elementData[elementCount++] = obj;

2.pop(出栈)

逻辑:删除并返回数组最后一位,数组长度减 1

public synchronized E pop() { // 线程安全
    int len = size();
    E obj = peek(); // 获取栈顶
    removeElementAt(len - 1); // 删除数组最后一个元素
    return obj;
}

3.peek(查看栈顶)

逻辑:直接返回数组最后一位元素,不修改结构

public synchronized E peek() {
    int len = size();
    if (len == 0) throw new EmptyStackException();
    return elementAt(len - 1); // 访问数组最后一位
}

4.empty(判空)

public boolean empty() {
    return size() == 0; // 判断数组长度是否为0
}

5.search(查找元素)

逻辑:从栈顶(数组尾部)往栈底(数组头部)查找

public synchronized int search(Object o) {
    int i = lastIndexOf(o); // 数组反向查找
    if (i >= 0) return size() - i; // 返回栈中的位置(栈顶为1)
    return -1;
}

6.底层数据结构图解

数组下标:    0        1        2        3  <-- 栈顶(push/pop/peek 都操作这里)
元素:      [A]      [B]      [C]      [D]
栈结构:    栈底     ->        ->        栈顶
  • 栈底 = 数组头部
  • 栈顶 = 数组尾部
  • 所有操作都是O (1) 时间复杂度(数组随机访问)

5.总结

1. 优点

  • 实现简单,直接复用动态数组;
  • 线程安全(所有读写方法加了 synchronized 锁);
  • 自动扩容,无需手动管理容量。

2. 缺点(重要!开发不推荐使用)

  1. 性能差:锁机制导致多线程下效率低;
  2. 继承设计不合理:Stack 继承 Vector,暴露了大量非栈操作(如 add(int index)),破坏栈的封装性;
  3. 官方不推荐:Java 官方明确建议使用 Deque 替代 Stack。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐