1. 递归调用
所谓递归方法的调用,即在定义的方法体中运行方法本身,下面示例中run
方法体又调用了run
方法:
public class RecursiveMethodCall {
public void run() {
run();
System.out.println("123");
}
public static void main(String[] args) {
RecursiveMethodCall rmc = new RecursiveMethodCall();
rmc.run();
}
}
2. 内存溢出
上面示例代码是可以正常编译的,但是运行就会报内存溢出(StackOverflowError)错误,其原因在于方法地递归调用是一个死循环,导致栈中不断地开辟新空间给run
方法,这也就是我们常说的压栈。
细心的同学可能会问,当初我们在学习流程控制时,while (true)
循环不也是死循环么,它为什么可以正常执行呢?
public class RecursiveMethodCall {
public void run() {
System.out.println("123");
}
public static void main(String[] args) {
RecursiveMethodCall rmc = new RecursiveMethodCall();
while (true) {
rmc.run();
}
}
}
显然,在主程序中所调用的rmc.run
方法,其在栈中指向的地址是一样的,并不会因为循环而去开辟新的空间。但是,run
方法中递归调用run
方法,是会开辟新的空间给递归的run
方法,所以内存会溢出。
3. 递归经典案例一:斐波那契数列
上面方法的递归调用其实是一个错误的示例,演示它的目的并不是告诉大家不要进行方法的递归调用。在某些情况下,使用方法的递归调用可以极大地减少代码量以及提高运行效率,接下来我们就介绍一个递归经典案例——斐波那契数列。
:::info
🧰 斐波那契数列
—————————————
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610….
:::
public class Recursion {
public long fibonacci(long n) {
if (n == 1 || n == 2) {
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
public static void main(String[] args) {
Recursion recursion = new Recursion();
int n = 3;
long number = recursion.fibonacci(n);
System.out.println(n + ": " + number);
}
}
4. 递归经典案例二:阶层
public class Recursion {
public long factorial(long n) {
if (n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
public static void main(String[] args) {
Recursion recursion = new Recursion();
int n = 3;
long number = recursion.factorial(n);
System.out.println(n + ": " + number);
}
}