“嗨,Amigo。今天 Bilaabo 将向您介绍递归。”

递归 - 1

如您所知,在 Java 中,一些方法会调用其他方法。此外,当一个方法被调用时,特定的参数被传递给它,但是方法的局部变量在它运行时采用特定的值。

“嗯。”

“正如你所知,不同方法的内部变量是相互独立的。”

“嗯。”

“所以想象一下方法调用自身的情况。这称为递归。例如:”

例子
public static void main(String[] args)
{
 countDown(10);
}

public static void countDown(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown(x - 1);
 }
}
屏幕输出:
10
9
8
7
6
5
4
3
2
1
Boom!

“我可以看到该方法在代码中调用了自身,但老实说我不明白发生了什么。”

“好吧,当调用不同的方法时会发生同样的事情。”

“不,我问的是变量会发生什么?它们的值会怎样?我们如何退出该方法?还是一次性退出所有内容?”

“天哪。一切都简单多了。想象一下,调用自身的方法被乘以了很多次。那么我们就会遇到类似的情况:”

递归方法调用 真正发生了什么
public static void main(String[] args)
{
 countDown(10);
}

public static void countDown(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown(x - 1);
 }
}
public static void main(String[] args)
{
 countDown1(10);
}

public static void countDown1(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown2(x - 1);
 }
}
public static void countDown2(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown3(x - 1);
 }
}
public static void countDown3(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown4(x - 1);
 }
}

public static void countDown4(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown5(x - 1);
 }
}
屏幕输出: 屏幕输出:
3
2
1
Boom!
3
2
1
Boom!

“换句话说,每次调用一个方法(甚至调用它自己)时,都会创建新变量来存储该方法的数据。没有共享变量。”

“每次调用时,都会在内存中创建具有新值的方法参数的另一个副本。当我们返回到旧方法时,它的变量会在那里使用。换句话说,在递归期间我们实际上调用了另一个方法,但是使用和我们的代码一样!

“我明白了。退出这种方法是如何工作的?也许是一个例子?”

“好的。一个例子胜过一千个字。”这是你的例子:

递归方法调用 递归方法调用
public static void main(String[] args)
{
 print(3);
}

public static void print(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  print(x - 1);
  System.out.println(x);
 }
}
public static void main(String[] args)
{
 print1(3);
}

public static void print1(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  print2(x - 1);
  System.out.println(x);
 }
}

public static void print2(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  print3(x - 1);
  System.out.println(x);
 }
}

…
屏幕输出: 屏幕输出:
3
2
1
Boom!
1
2
3
3
2
1
Boom!
1
2
3

“好的。我想我明白了。为什么我们需要递归?”

“有很多很多任务可以分成与原始任务相同的单独子任务。例如,您需要遍历 XML 树的所有元素。每个元素可以有几个子元素,它们有自己的子元素自己的子元素。”

“或者你需要显示一个目录及其所有子目录中的文件列表。所以你写了一个方法来显示当前目录的文件。然后要获取所有子目录的文件,你调用你的方法使用不同的论点:一个子目录。”

“例如:”

显示目录及其子目录中的所有文件
public static void main(String[] args)
{
 printAllFiles(new File("c:/windows/"));
}

public static void printAllFiles(File dir)
{
 for (File file : dir.listFiles())
 {
  if (file.isDirectory())
   printAllFiles(file);
  else
   System.out.println(file.getAbsolutePath());
 }
}

“第 8 行——我们获取 dir 目录中所有文件(和目录)的列表。”

“第 10-11 行——如果文件实际上是一个目录,那么我们再次调用printAllFiles,但这次有另一个参数:子目录。”

“第 13 行——我们显示当前文件的名称。”

“好的。我想我明白了。谢谢你,Bilaabo。”