【JavaSE专栏17】用最简单的方法,实现 Java 的堆栈

简介: 【JavaSE专栏17】用最简单的方法,实现 Java 的堆栈

堆栈是 Java 常见的数据结构,本文将对 Java 中的 堆栈进行讲解。

一、实现 Java 堆

在Java编程语言中,(Heap)是一种内存分配机制,用于存储动态分配的对象。

堆是在Java虚拟机(JVM)运行时创建和管理的一个区域,它具有自动内存管理的特性。

堆的主要特点包括:

  • 动态分配:堆可以根据需要动态分配和释放内存。
  • 对象存储:堆用于存储创建的Java对象。
  • 垃圾回收:堆通过垃圾回收机制来自动管理内存,当某个对象不再被引用时,垃圾回收器会自动回收这些对象占用的内存空间。

以下是一个简单的Java代码示例,展示了如何在堆中创建对象:

public class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 省略getter和setter方法
    public static void main(String[] args) {
        // 在堆中创建Person对象
        Person person = new Person("Alice", 25);
        // 使用person对象
        System.out.println(person.getName() + " is " + person.getAge() + " years old.");
    }
}

在上面的示例中,我们定义了一个 Person 类,并使用构造函数在堆中创建了一个 Person 对象

然后,我们可以使用该对象进行各种操作,例如获取和设置对象的属性。

当程序执行结束后,Java 虚拟机会自动回收不再使用的内存空间。


二、实现 Java 栈

Java语言的栈(Stack)是一种基于后进先出(LIFO)原则的数据结构。

它类似于现实生活中的堆栈,只能在一端进行插入和删除操作,这一端被称为栈顶

栈具有两个主要的操作:

  • 入栈(Push):将元素放入栈顶。
  • 出栈(Pop):从栈顶移除一个元素。

以下是一个简单的Java代码样例,实现了栈的基本功能:

public class Stack {
    private int maxSize; // 栈的最大容量
    private int[] stackArray;
    private int top; // 栈顶指针
    public Stack(int size) {
        maxSize = size;
        stackArray = new int[maxSize];
        top = -1; // 初始化栈顶指针为-1,表示栈为空
    }
    public void push(int value) {
        if (isFull()) {
            System.out.println("栈已满,无法进行入栈操作");
            return;
        }
        stackArray[++top] = value; // 将元素插入栈顶,并将栈顶指针加1
    }
    public int pop() {
        if (isEmpty()) {
            System.out.println("栈为空,无法进行出栈操作");
            return -1;
        }
        return stackArray[top--]; // 返回栈顶元素,并将栈顶指针减1
    }
    public int peek() {
        if (isEmpty()) {
            System.out.println("栈为空");
            return -1;
        }
        return stackArray[top]; // 返回栈顶元素,不改变栈顶指针
    }
    public boolean isEmpty() {
        return (top == -1); // 判断栈是否为空
    }
    public boolean isFull() {
        return (top == maxSize - 1); // 判断栈是否已满
    }
    public static void main(String[] args) {
        Stack stack = new Stack(5);
        stack.push(10);
        stack.push(20);
        stack.push(30);
        stack.push(40);
        System.out.println(stack.pop()); // 输出:40
        System.out.println(stack.peek()); // 输出:30
        System.out.println(stack.isEmpty()); // 输出:false
        System.out.println(stack.isFull()); // 输出:false
    }
}

以上代码演示了如何使用数组实现一个简单的栈,并进行入栈、出栈、查看栈顶元素以及判断栈是否为空或已满的操作。


三、Java 堆栈的区别和联系

在Java中,栈(Stack)和堆(Heap)是两个不同的概念,它们具有不同的作用和特点。

3.1 区别

  • 数据结构:栈是一种线性数据结构,遵循后进先出(LIFO)原则;而堆是一种动态内存分配的数据结构,用于存储对象。
  • 存储内容:栈存储基本类型和对象的引用,以及方法调用时的局部变量和方法执行时的调用栈信息;堆存储对象的实例和数组等动态分配的数据。
  • 内存管理:栈由编译器自动分配和释放,大小固定且较小;堆由开发人员手动或自动进行动态分配和释放,大小可变且较大。

3.2 联系

  • 关联性:在Java程序中,栈中保存着对堆中对象的引用。当我们创建一个新对象时,该对象将被分配到堆上,并在栈上创建一个指向堆上对象的引用。
  • 生命周期:栈上的数据随着方法的调用和返回而自动分配和释放,具有短暂的生命周期;堆上的数据可以在任何地方被引用,具有更长久的生命周期,直到没有引用指向该对象时才会被垃圾回收机制回收。
  • 协同使用:栈和堆在程序执行中相互协作。方法调用时,局部变量在栈上分配内存;方法中创建的对象则在堆上分配内存,并由栈上的引用指向这些对象。

3.3 区别联系小结

栈和堆在Java中是两个不同的概念,栈用于存储基本类型、方法调用信息和对象引用,而堆用于存储动态分配的对象

它们在数据结构、存储内容、内存管理等方面有着明显的区别,但也存在联系,如栈中保存堆中对象的引用,以及栈和堆的协同使用。


四、总结

本文简单对 Java 中的堆栈数据结构进行了介绍,讲解了堆栈实现原理,并给出了样例代码。在下一篇博客中,将讲解 Java 中的内存机制。

相关文章
|
8天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
41 4
|
19天前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
39 17
|
13天前
|
Java 测试技术 Maven
Java一分钟之-PowerMock:静态方法与私有方法测试
通过本文的详细介绍,您可以使用PowerMock轻松地测试Java代码中的静态方法和私有方法。PowerMock通过扩展Mockito,提供了强大的功能,帮助开发者在复杂的测试场景中保持高效和准确的单元测试。希望本文对您的Java单元测试有所帮助。
18 2
|
20天前
|
人工智能 Oracle Java
解决 Java 打印日志吞异常堆栈的问题
前几天有同学找我查一个空指针问题,Java 打印日志时,异常堆栈信息被吞了,导致定位不到出问题的地方。
30 2
|
21天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
15 3
|
23天前
|
Java 大数据 API
别死脑筋,赶紧学起来!Java之Steam() API 常用方法使用,让开发简单起来!
分享Java Stream API的常用方法,让开发更简单。涵盖filter、map、sorted等操作,提高代码效率与可读性。关注公众号,了解更多技术内容。
|
21天前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
14 2
|
21天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
14 1
|
21天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
27 1
|
21天前
|
Java
在Java多线程编程中,`wait()`和`notify()`方法的相遇如同一场奇妙的邂逅
在Java多线程编程中,`wait()`和`notify()`方法的相遇如同一场奇妙的邂逅。它们用于线程间通信,使线程能够协作完成任务。通过这些方法,生产者和消费者线程可以高效地管理共享资源,确保程序的有序运行。正确使用这些方法需要遵循同步规则,避免虚假唤醒等问题。示例代码展示了如何在生产者-消费者模型中使用`wait()`和`notify()`。
22 1