2012-10-22 61 views
1

我有一個代碼段,真的很難理解這種遞歸模式。奇怪的Java遞歸代碼

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包含一個目錄的路徑,在該目錄中它有幾個子目錄和文件。

因此文件[]數組的樣子,

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取代。當代碼執行進入循環時,它將轉到其他部分,因爲它找到.settings目錄中的文件。

一旦迭代了4次(因爲它只有4個文件),它會假設完成循環。

但奇怪的是DataDirectory目錄值過得去舊的價值它有取代並開始撥打下一個項目有數組中以前(這是構建目錄)。

有人可以解釋爲什麼它發生那樣,沒有完成循環..我希望我解釋清楚,如果沒有請問我。

非常感謝。

+0

腳本的輸出是什麼?從你所描述的內容看,它看起來像是完成了'.settings'的循環,然後退出'indexDirectory',從而繼續循環查找'dataDirectory' ... –

+0

想象一下,調用完全不同的方法而不是'indexDirectory'。調用完成後,您當然希望完全像以前一樣繼續執行所有變量。遞歸中沒有魔法,唯一的區別是調用了相同的方法。 –

回答

0

一旦迭代了4次(因爲它只有4個文件),它假設完成循環。

但奇怪的是DataDirectory目錄值過得去舊的價值它有取代並開始撥打下一個項目有數組中以前(這是建立目錄)。

這是遞歸究竟如何是應該工作。

你在某種程度上是正確的,一旦indexDirectory(?, ".settings", ?)的調用看到了四個文件,它應該停止循環並終止該方法。那是這樣的,其實這就是發生了什麼。該方法在那一點完成,控制權返回給它的調用者。

然而,打電話的是另一個indexDirectory呼一平「上漲」。 呼叫遍歷項C:\projects\test\,和剛剛結束對付.settings項目,它碰到。所以一旦這個方法返回,它就繼續從它之前的位置(遞歸地)調用indexDirectory.settings

因此,正如人們所期望的那樣,它會索引C:\projects\test\build等等。

爲了澄清更多一些,的dataDirectory的值沒有被精確取代。實際發生的情況是,這個參數一次有兩個副本 - 兩個嵌套方法調用中的每一個。內在。遞歸方法的值爲.settings,外部方法的值爲test。內部方法訪問其四個文件並返回後,控制權返回到外部方法 - 對於dataDirectory,該方法(仍然)的值爲test

3

當方法indexDirectory被第一次調用時,它裏面有8個文件(包括目錄)。

所以,你的for循環for (File file : files) {將迭代至少8次。 (A)

現在,內8個文件,.settings發現這是目錄。並且您正確理解它會被拒絕 - 使用dataDirectory = .settings調用indexDirectory。在這一點上,5次迭代從狀態(A)未決

當,遞歸調用完成時,控制數達到到狀態(A)和迭代第四與DataDirectory目錄=構建開始。

的堆棧幀將是如下:

enter image description here

幀2完成後,第1幀將恢復其執行。

1

這就是遞歸的工作原理。在遍歷頂級目錄的同時,一切正常,直到循環遇到目錄。當它遇到一個目錄時,它進入一個更深的循環,但它知道它沒有完成外部循環。一旦它完成內部循環(以及內部循環中的任何其他內部循環),它就會返回並完成外部循環。

想象一下,你在一個有很多門的房間裏。當您轉動門上的旋鈕時,會彈出一個標誌。其中一些門通向其他房間(屋內更深處),但大多數門都掛在牆上。您必須轉動每個門把手上的旋鈕。如果它打開到另一個房間,則必須轉動每扇門上的旋鈕。當所有的旗幟都在內部房間上時,你可以回到外面的房間並旋轉旋鈕直到所有的旗幟向上。當所有的標誌都起來了,你又回到了最外層的房間時,你的工作就完成了。

hth

0

您正在遞歸調用indexDirectory。因此,在完成更深的目錄之後(在本例中是.settings),它將繼續完成循環。