奇怪的Java递归代码

时间:2012-10-22 11:21:30

标签: java recursion

我有一个代码片,并且很难理解这种递归模式。

private void indexDirectory(IndexWriter indexWriter, File dataDirectory,
                            String suffix) throws IOException {

    System.out.println("Data directory before: " + dataDirectory.getName());
    File[] files = dataDirectory.listFiles();

    for (File file : files) {
        System.out.println("File name : " + file.getName());
        if (file.isDirectory()) {
            indexDirectory(indexWriter, file, suffix);
        } else {
            indexFileWithIndexWriter(indexWriter, file, suffix);
        }
    }
    System.out.println("Data directory : " + dataDirectory.getName());
}

dataDirectory包含一个目录路径,其中包含多个子目录和文件。

所以files []数组看起来像,

C:\projects\test\.classpath, 
C:\projects\test\.project, 
C:\projects\test\.settings, 
C:\projects\test\build, 
C:\projects\test\build.xml, 
C:\projects\test\dist, 
C:\projects\test\src, 
C:\projects\test\WebContent

.classpath .project 是文件,而 .settings 是包含4个文件的目录。因此当第三次迭代进入 .settings 目录时,它的内部有4个文件。由于.settings是一个目录, file.isDirectory 正在获得 true 并且相同的方法(indexDirectory)将使用最新的参数值进行调用。因此, dataDirectory 值会被 .settings 取代。当代码执行进入循环时,它将转到 else 部分,因为它在 .settings 目录中找到了它的文件。

一旦迭代4次(因为它只有4个文件),它就会完成循环。

但奇怪的是, dataDirectory 值被它所拥有的旧值替换,它开始调用之前的数组中的下一个项目( build 目录)。

有人可以解释我为什么会这样发生,而不是完成循环..我希望我能清楚地解释它,如果没有请问我。

非常感谢。

4 个答案:

答案 0 :(得分:3)

当第一次调用方法indexDirectory时,它内部有8个文件(包括目录)。

因此,你的for循环for (File file : files) {将至少迭代8次。的(A)

现在,在8个文件中,找到了 .settings ,这是目录。并且你正确地理解它将使用dataDirectory = .settings重新调用indexDirectory。此时,状态(A)

正在等待5次迭代

当递归调用完成时,控件到达状态(A),第四次迭代以dataDirectory = build开始。

堆栈帧如下:

enter image description here

第2帧完成后,第1帧将恢复执行。

答案 1 :(得分:1)

这就是递归的工作原理。在循环访问顶级目录时,一切正常,直到循环遍历目录。当它遇到一个目录时,它进入一个更深的循环,但它知道它还没有完成外部循环。一旦它完成了内部循环(以及其内部的任何其他内部循环),它就会返回并完成外部循环。

想象一下,你在一个有很多门的房间里。当您转动门上的旋钮时,会弹出一个标记。其中一些门通向其他房间(房屋内部较深处),但大多数只是悬挂在墙上。你必须转动每个门把手上的旋钮。如果它通向另一个房间,你必须转动每个门上的旋钮。当所有的旗帜都在内室时,你可以回到外面的房间并完成转动旋钮,直到所有的旗帜都朝上。当所有旗帜都已启动并且您回到最外层的房间时,您的工作就完成了。

HTH

答案 2 :(得分:0)

  

一旦迭代4次(因为它只有4个文件),它就会完成循环。

     

但奇怪的是,dataDirectory值被它所拥有的旧值替换,它开始调用之前在数组中的下一个项目(这是构建目录)。

这正是递归假设的工作方式。

你在某种程度上是正确的,一旦indexDirectory(?, ".settings", ?)的调用看到了四个文件,它就应该停止循环并终止该方法。就是这样,实际上这就是发生的事情。该方法在该点完成,并且控制权返回给其调用者。

然而,来电者是另一个indexDirectory呼叫一级“更高”。 调用正在迭代C:\projects\test\中的项目,并刚刚处理了它遇到的.settings项目。因此,一旦该方法返回,它就会继续({递归)在indexDirectory上调用.settings之前的位置。

因此,正如人们所期望的那样,它会将C:\projects\test\build编入索引,依此类推。

为了澄清更多内容,dataDirectory的值并非完全被替换。实际发生的是,这个参数有两个副本 - 一个用于两个嵌套方法调用。内心的。递归方法的值为.settings,外部方法的值为test。一旦内部方法访问了它的四个文件并返回,控制就会返回到外部方法 - test的值仍然是dataDirectory

答案 3 :(得分:0)

您正在递归调用indexDirectory。因此,在完成更深层目录(在此示例中为.settings)之后,它将继续完成循环。