一个简单的代码段,用于计算以下数字的阶乘:
public class Main{
static int factorial(int number){
System.out.println("At factorial("+number+")");
if (number == 1){
return 1;
}
return number * factorial(number-1);
}
public static void main(String[] args){
System.out.println("factorial(4) = "+ factorial(4));
}
}
在这里,我认为当数字的值变为1(由于递归)时,它每次返回1并且中断方法并打印1.但是,它确实返回适当的因子值? 按照这个:Java - Does returning a value break a loop?,它不应该每次都返回1吗?这两个代码片段在返回值时有何不同?
谢谢
答案 0 :(得分:1)
我试图解释整个过程;请参阅this source。
在此之前,您应该对调用堆栈,递归和堆栈帧有基本的了解。
调用堆栈是程序用来存储有关活动子例程的信息的数据结构。拥有调用堆栈的主要原因是程序可以跟踪子程序在完成执行后应该将控制权返回的位置。
堆栈帧是调用堆栈的一部分,每次调用子例程时都会创建一个新的堆栈帧。因此,在上面的递归factorial()
方法中,每次调用方法时都会创建一个新的堆栈帧。堆栈帧用于存储一个例程调用的所有变量。所以,请记住,调用堆栈基本上是一堆堆栈帧。
让我们将过程分为4个部分,因为选择的数字是4。
static int factorial(4){
if (4 == 1){
return 1;
}
return 4 * factorial(3);
}
static int factorial(3){
if (3 == 1){
return 1;
}
return 3 * factorial(2);
}
static int factorial(2){
if (2 == 1){
return 1;
}
return 2 * factorial(1);
}
static int factorial(1){
if (1 == 1){
return 1;
}
return 2 * factorial(number-1);
}
您可以看到第一个堆栈框架的编号等于4。
然后调用了factorial(3)
- 因此第一次调用factorial(4)
并未完成,因为在第一次调用之前会进行另一次调用(factorial(3)
)到factorial
可以跑到完成。
其他人也是如此。
堆栈帧用于保存第一次调用factorial()
的状态。它存储当前调用factorial()
的本地函数变量(及其值),它还将存储调用它的方法的返回地址(因为我们正在讨论第一次非递归调用factorial()
,首先调用的factorial()
例程是Factorial在完成所有内容时将返回的内容)。
因为堆栈帧也存储了返回地址,所以factorial()
函数知道完成运行后返回的位置
最后,在 4th 堆栈框架中,我们遇到了我们的基本案例
表示递归调用已完成,然后返回控制权
第三堆栈帧,其中factorial(1) * 2
计算为
2
,然后将控制权返回到第二堆栈框架,其中factorial(2) * 3
计算为6
,然后控制权为
返回到factorial(3) * 4
所在的第一个堆栈框架
计算为24
。最后,返回24
的结果。