递归保留值中的局部变量?

Local variable in recursion retaining values?

目前正在研究递归 practice/implementation 并注意到一些与我所知道的在编程中真实存在的一切相悖的东西。

递归方法

protected int getArea() {

    if(width <= 0)
        return 0;
    else if(width == 1)
        return 1;
    else {

        Triangle t2 = new Triangle(width - 1);
        int area = t2.getArea();//Area variable somehow is holding the values of previous calls, despite being instantiated in each new call?

        return area + width;

    }

}

不知何故,局部变量 area 正在聚合递归方法中先前调用的值。这怎么可能,每次调用都被实例化?在每次调用中,方法 getArea() 似乎再次被调用,由于 getArea() 调用发生在 before 方法 return 语句。

这是怎么回事?

每个方法调用的详细信息都存储在堆栈中,一旦从方法调用返回的值执行returns到调用当前方法的前一个方法,局部变量值等。将存储在堆栈中,这就是程序需要时在执行中使用这些值的方式。围绕递归程序进行一些实验以了解更多信息。

我的建议是尝试使用 IDE 上的断点调试递归程序,例如 eclipse 或 Intellij,这会消除很多混淆并使递归的工作原理更加清晰。

当谈到递归时,我经常发现记住 你所给予的就是你所得到的,这意味着当你调用你的递归方法时你得到的就是你得到的任何东西决定从中return。

在这种情况下,你写什么就得到什么

int area = t2.getArea();

01area + width

最后一种情况是递归情况,您递归地定义一个新的 Triangle 实例,新宽度减 1,然后对其调用 .getArea()。这在功能上等同于将 .getArea() 定义为

protected int getArea(int width) {

    if(width <= 0)
        return 0;
    else if(width == 1)
        return 1;
    else {
        int area = getArea(width - 1);
        return area + width;
    }

}

Triangle 的一个实例或另一个实例调用 .getArea() 没有区别。重要的是 you 在调用它时定义 width 是什么(在本例中 width - 1)以及 you定义它对 return 值的影响。

我认为你看错了。如果调用两个方法。例如。

public int test() {
    int x = getSomeInt(1);
    int y = getSomeInt(2);
    return x + y;
}

你有没有想过return x + y是否完成,或者x的值是否在y之前确定?它从上到下执行,语句设置 ygetSomeInt(1) 已 returned 且其值设置为 x 之前不会启动。 所以对于你的例子:

protected int getArea() {
    if (width <= 0) {
        return 0;
    } elseif (width == 1) {
        return 1;
    } else {
        Triangle t2 = new Triangle(width - 1);
        int area = t2.getArea();
        return area + width;
    }
}

因此,如果您有一个宽度为 1 的三角形并调用 getArea,您将返回 1

如果你在宽度为 2 的三角形上做,会发生什么?那么它创建 t2 宽度 1 并在其上调用 getArea 。我们已经知道结果,因为我们已经计算过了。 area 变成 1 然后 return 变成 1 + 2

如果你使用宽度 3 会发生什么?。它将创建宽度为 2t2 并在其上调用 getArea()。我们从上面知道returns 3,结果是3 + 3

递归方法以高 with 调用,但首先确定的是具有 1 的方法,然后是 2、3、4,...最后调用你实际调用的有一些 area 并将其 with 添加到。

对方法的每次调用与被调用者没有任何关系。是的,它是相同的代码,但它是一个不同的对象,局部变量对于调用是唯一的,就像两个调用 getSomeInt 也有两个不同版本的第一个参数。除非您正在改变或通过引用传递,否则它们不会纠缠在一起。

在对象上调用方法与对象作为调用中的参数非常相似。递归调用有一个 width 较小的对象,并且在某一时刻它会达到基本情况。你可以说这是一样的:

public static int getArea(Triangle t) {
    if (t.width <= 0) {
        return 0;
    } elseif (t.width == 1) {
        return 1;
    } else {
        Triangle t2 = new Triangle(t.width - 1);
        int area = getArea(t2);
        return area + t.width;
    }
}

再说一遍.. 递归方法不会改变任何东西。它啊没有特殊处理。它需要先完成调用才能 return 值,就像您使用不同的方法获取 getArea 中的区域一样。完全没有区别。