Java Switch语句-JVM内存分配、堆栈溢出

Java Switch语句-JVM内存分配、堆栈溢出,java,Java,我在学校上Java课。我们的任务是设计一个类作为菜单,有几个子菜单 结构有点像这样(下面是一种伪代码,只是为了显示结构): 我的问题是:我的老师说这是错误的,因为如果我这样做,JVM会在内存中存储程序从一个地方到另一个地方的路径,从长远来看,这会导致堆栈溢出。他没有解释清楚,他只是说我应该用一个使用布尔变量的while循环来围绕整个过程,添加一个选项来翻转该布尔值以退出while循环,因为这样Java就不会存储程序从一个方法到另一个方法的路径 再一次,他没有详细解释,而且他解释的方式听起来非常混

我在学校上Java课。我们的任务是设计一个类作为菜单,有几个子菜单

结构有点像这样(下面是一种伪代码,只是为了显示结构):

我的问题是:我的老师说这是错误的,因为如果我这样做,JVM会在内存中存储程序从一个地方到另一个地方的路径,从长远来看,这会导致堆栈溢出。他没有解释清楚,他只是说我应该用一个使用布尔变量的while循环来围绕整个过程,添加一个选项来翻转该布尔值以退出while循环,因为这样Java就不会存储程序从一个方法到另一个方法的路径

再一次,他没有详细解释,而且他解释的方式听起来非常混乱(根据他给我的信息,我试图尽可能清楚地解释)。在过去的3个小时里,我一直在网上寻找任何与他告诉我的相似的东西,但我找不到任何东西……所以我决定请教专家

你们能帮帮我吗?

是的,你们的老师(部分)是对的。 关键的部分是,您可能从
submenu1()
中调用
mainMenu()
,并从
submenu1()中调用
submenu1()
。 如果每次在
子菜单()中调用
mainMenu()
,并在
mainMenu()中调用
子菜单()
,则程序将崩溃

对于每个函数调用,底层系统需要为函数的局部变量等保留内存。这就是所谓的stackframe。当您从函数本身(直接或间接)调用函数时,会调用它。递归需要在某个点返回。如果没有,您会因为内存不足而出现堆栈溢出。

是的,您的老师(部分)是正确的。 关键的部分是,您可能从
submenu1()
中调用
mainMenu()
,并从
submenu1()中调用
submenu1()
。 如果每次在
子菜单()中调用
mainMenu()
,并在
mainMenu()中调用
子菜单()
,则程序将崩溃


对于每个函数调用,底层系统需要为函数的局部变量等保留内存。这就是所谓的stackframe。当您从函数本身(直接或间接)调用函数时,会调用它。递归需要在某个点返回。如果没有,则由于内存耗尽而导致堆栈溢出。

当计算机执行方法/函数调用时,它必须:

  • 记住调用函数正在做什么——局部变量的值,以及在被调用函数完成时在何处恢复执行
  • 将控制转移到被调用函数
  • 被调用函数完成后,它将:

  • 将控制返回到调用函数中记忆的位置;好了,它
  • 恢复局部变量的值等。;及
  • 继续处理从被调用函数返回的值(如果有)
  • 您的函数系统存在的问题是,它们可以一直调用,而且永远不会返回:

    主菜单->子菜单1->主菜单->子菜单1。。。等等等等

    如果您的函数从未返回,那么每次您进行新调用时,它只需不断记住越来越多的内容,可能在某个点超过可用于存储这些内容的(堆栈)内存量,从而导致堆栈溢出错误

    有些语言实现了一种称为“tail call optimization”的优化,当调用另一个函数是您的函数所能做的最后一件事时,这种优化实际上可以避免存储这些内容。在这种情况下,它不再需要局部变量的值,也不需要记住在哪里恢复,因为它可以在调用函数中恢复,而调用函数已经被记住了


    在这样的语言中,您的代码实际上可以正常运行。。。但是java不是这些语言之一。

    当计算机执行方法/函数调用时,它必须:

  • 记住调用函数正在做什么——局部变量的值,以及在被调用函数完成时在何处恢复执行
  • 将控制转移到被调用函数
  • 被调用函数完成后,它将:

  • 将控制返回到调用函数中记忆的位置;好了,它
  • 恢复局部变量的值等。;及
  • 继续处理从被调用函数返回的值(如果有)
  • 您的函数系统存在的问题是,它们可以一直调用,而且永远不会返回:

    主菜单->子菜单1->主菜单->子菜单1。。。等等等等

    如果您的函数从未返回,那么每次您进行新调用时,它只需不断记住越来越多的内容,可能在某个点超过可用于存储这些内容的(堆栈)内存量,从而导致堆栈溢出错误

    有些语言实现了一种称为“tail call optimization”的优化,当调用另一个函数是您的函数所能做的最后一件事时,这种优化实际上可以避免存储这些内容。在这种情况下,它不再需要局部变量的值,也不需要记住在哪里恢复,因为它可以在调用函数中恢复,而调用函数已经被记住了


    在这样的语言中,您的代码实际上可以正常运行。。。但是java不是这些语言中的一种。

    请尝试使您的示例更符合java语法。目前,它看起来不像方法调用,但这似乎就是您的问题所在。那样的话,你的老师是对的。回想一下,方法调用是可以返回的,以恢复调用方法中的执行。当然,这是一种能力
    public static void mainMenu() {
    
    switch(integer variable){
    
    case 1: submenu1();
    break;
    case 2: submenu2();
    break;
    }
    }
    
    
    
    public static void submenu1() {
    
    switch(integer variable){
    
    case 1: subsubmenu1();
    break;
    case 2: subsubmenu2();
    break;
    default: mainMenu(
    }
    }
    
    
    public static void subsubmenu1() {
    
    switch(integer variable) {
    case 1:  anothersubmenu1()
    break;
    case 2:  anothersubmenu2();
    break;
    default: submenu1();
    }
    }