2016-07-31 45 views
0

我一直在想是否有可能在Java中構建一個自遞歸類。顯然,它是。自遞歸類拼圖

public class Void { 
    static Inher i = new Inher(); 

    static { 
     System.out.println("ok"); 
    } 

    public static void main (String... args) {} 

    private static class Inher extends Void {}  
} 

但是,我期望堆棧溢出或其他一些失敗,我得到的只是一個「好」在終端。我錯過了什麼或者錯了什麼?如何理順它並獲得適當的溢出?如果不是太廣泛,你對這個問題有任何想法嗎?

一個小說明

我想這個代碼永遠複製基本類中的內部類,那麼內部類的內部類,等等。在某些時候,結構會比內存大。那是我失敗的意圖。

+0

你意識到你可能會錯過的是獲得「溢出」是不正確的,對吧? –

+0

@ScottHunter這個類應該是失敗的,但它是雙重的。你可以給出任何確切的提示,讓它永遠沉浸在遞歸中,或者只是解釋爲什麼這是不可能的? – tomasz

+0

你應該解釋爲什麼你覺得這會失敗。我不明白你爲什麼這麼想。 –

回答

1

除其他措施,編譯器以這種方式工作(簡體):

  • 代碼
  • 解析代碼的詞法分析和構建抽象語法樹
  • 類型檢查
  • 雜項優化
  • 生成機器碼(在這種情況下是Java字節碼)

在類型檢查過程中,編譯器會檢查類型是否匹配並存在;在代碼生成期間,它將創建包含用戶定義類的列表的VMT

解析步驟只執行一次並遞歸執行,但它不會按照您預期的方式工作;它將在這裏執行的是它將看到類Void並將其添加到類的列表中,然後它將檢查內部並看到Inher。它看到Inher延伸VoidVoid可從當前範圍訪問;因此它在VMT中添加了這個新類。

如果您在任何時候創建了Inher的實例,它將驗證您是否在Void函數的範圍內。但編譯器不會執行遞歸檢查,因爲它不會返回檢查以前的類,並遞歸地生成將溢出的VMT。它將它們分開處理,並基於當前的上下文。這就是編譯成功的原因,因爲它只是範圍和類型檢查的問題。

請注意,這裏的Inher是類聲明,並且不是實例。如果你創造了Void類是Inher類型內的成員,與Inher延長Void,你要麼已經獲得了編譯失敗或堆棧溢出,因爲Void類的每個分配將創建一個新Inher,這將本身分配一個新的,等等。但是在這裏,你只是定義了一個類,這樣的操作在任何時刻都不需要遞歸構造;它因此編譯。

在執行時,它是同樣的事情;堆棧溢出發生的唯一方式是如果存在一些遞歸分配代碼;但類定義不需要任何分配的內存,除了在代碼生成步驟中成功構建的VMT之外。所以不會出現任何異常。

+0

一個不同的,也許更簡單的方式來解釋這個:你的代碼基本上意味着一個'Inher'是一個'Void',你只能在'Void'範圍內聲明一個'Inher'。從來沒有說過'Void'包含'Inher',所以不會出現問題。 – pie3636

+1

謝謝。我明天會閱讀並分析你的答案。它看起來很有趣。 – tomasz

+0

現在已經很晚了,我寫這個很急,所以請隨時詢問它的任何部分是否不清楚或對您沒有意義。 – pie3636