目前正在从事递归实践/实现,并且发现有些事情与我在编程中所知的一切都是相反的。
递归方法
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()
,由于area
调用发生在方法之前 ,从而阻止了getArea()
变量持有任何东西。 return
语句。
这是怎么回事?
答案 0 :(得分:3)
每个方法调用的详细信息都存储在堆栈中,一旦从方法调用返回值,执行就会返回到调用当前方法的前一个方法,局部变量值等。将被存储在堆栈中,这就是程序需要时在执行中使用这些值的方式。对递归程序进行一些实验,以了解更多有关递归程序的信息。
我的建议是尝试使用IDE上的断点(如eclipse或Intellij)调试递归程序,这将消除很多混乱并清晰地说明递归的工作方式。
答案 1 :(得分:1)
当涉及到递归时,我经常会发现记住所付出的就是所得到的会很有帮助,这意味着调用递归方法时所得到的就是 you < / em>决定从中退回。
在这种情况下,您写作时会得到什么
int area = t2.getArea();
是0
,1
或area + 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;
}
}
从.getArea()
的一个实例或另一个实例调用Triangle
都没有区别。重要的是您在调用width
时将其定义为width - 1
,以及 you 如何定义其对收益的影响值。
答案 2 :(得分:0)
我认为您看错了。如果调用两种方法。例如。
public int test() {
int x = getSomeInt(1);
int y = getSomeInt(2);
return x + y;
}
您是否在质疑是否已完成return x + y
或在x
之前确定y
的值?它从上到下执行,并且语句设置y
在返回getSomeInt(1)
并将其值设置为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}}并在其上调用1
。我们已经知道结果了,因为我们已经对其进行了计算。 getArea
变为area
,然后返回1
。
如果宽度为3,会发生什么?它将创建宽度为1 + 2
的{{1}}并在其上调用t2
。我们知道从上面返回2
,结果为getArea()
。
以较高的3
调用回溯方法,但是首先确定具有3 + 3
的那个,然后是2,3,4,...,最后是您实际调用的调用有一些with
,它添加了1
。
每次对拟甲醇方法的调用与被叫方无关。是的,是相同的代码,但是它是一个不同的对象,并且局部变量对于该调用是唯一的,就像两个调用area
所调用的第一个参数也具有两个不同的版本一样。除非您通过引用进行更改或传递,否则它们不会纠缠在一起。
在对象上调用方法与对象在调用中作为参数非常相似。递归调用的对象具有较小的with
,并且在某一时刻它将命中基本情况。您可以说是一样的:
getSomeInt
同样,..具有恢复作用的方法不会更改任何内容。没什么特别的待遇。它需要先完成调用,然后才能返回值,就像您使用其他方法来获取width
中的区域一样。根本没有区别。