我有一个代码片,并且很难理解这种递归模式。
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 目录)。
有人可以解释我为什么会这样发生,而不是完成循环..我希望我能清楚地解释它,如果没有请问我。
非常感谢。
答案 0 :(得分:3)
当第一次调用方法indexDirectory
时,它内部有8个文件(包括目录)。
因此,你的for循环for (File file : files) {
将至少迭代8次。的(A)强>
现在,在8个文件中,找到了 .settings ,这是目录。并且你正确地理解它将使用dataDirectory = .settings重新调用indexDirectory
。此时,状态(A)
当递归调用完成时,控件到达状态(A),第四次迭代以dataDirectory = build开始。
堆栈帧如下:
第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)之后,它将继续完成循环。