簡體   English   中英

Java:繼承self的類

[英]Java : Class inheriting self

我知道這是毫無意義的:我發現它很有趣,我想更多地詢問當你創建一個繼承自身的類時會發生什么的機制,導致堆棧溢出崩潰。 令人驚訝的是Java允許您開始構建這樣的構造。

我只是在猜測,但JVM是否會將自己置於一個無限循環中,試圖在實例化之前解決該類,或者它是否實際上無休止地實現了該類的多個副本?

我應該更具體; 我使用內部類來從封閉類派生。

 public class Outside {
    private int outsideValue;

    public class Inside extends Outside {
        private int insideValue;
        public Inside(int val) {
            insideValue = val;
        }
    }

    public Outside() {
        Inside o = new Inside(0);
    }
}

public class Main {
    public static void main(String args[]) {
        Outside o = new Outside();
    }
}

請記住,因為Inside擴展Outside ,它有一個super()隱式調用,它是Outside的構造函數(它反過來調用Inside的構造函數),因此它會四處傳播。

您發布的代碼在概念上與以下程序沒有區別

class A {
    B b = new B();
}

class B extends A {
}

public class Test {
    public static void main(String[] args) {
        new A(); // Create an A...
                 //   ... which creates a B
                 //   ... which extends A thus implicitly creates an A
                 //   ... which creates a B
                 //   ...
    }
}

在最終形式中,這個問題與循環繼承和內部類無關。 它只是由未綁定的遞歸構造函數調用引起的無限遞歸。 通過以下簡單示例可以顯示相同的效果:

public class A {
    public A() {
        new A();
    }
}

請注意,此代碼完全有效,因為Java不對遞歸調用應用任何限制。

在你的情況下,由於繼承,它稍微復雜一些,但如果你還記得子類的構造函數隱式調用超類的構造函數,那么應該清楚這些調用形成無限遞歸。

嘗試像eclipse這樣的IDE,它不允許你這樣做。 即給出這樣的錯誤。

檢測到周期:類型Test無法擴展/實現自身或其自己的成員類型之一

擴展自己會產生循環繼承錯誤(java不允許)。 您的代碼示例已編譯並且有效。


由於弗拉基米爾·伊萬諾夫的堅持,我將修復我的編輯。

由於以下原因,您的代碼會拋出StackOverflowError

Inside o = new Inside(0);

由於Inside擴展OutsideInside首先隱式調用super()方法(因為你自己沒有調用它)。 Outside()構造函數初始化Inside o和周期再次運行,直到堆棧已滿,並且它溢(有太多的InsideOutside的堆棧內)。

希望這有助於弗拉基米爾伊萬諾夫。

嘗試進入循環繼承鏈時,java編譯器不會進入無限循環。 畢竟,每個繼承鏈都是最終有限的圖形(並且從計算上講,它具有非常少量的節點和邊緣。)更准確地說,從子類A到(最終)超類Z的繼承圖必須是一條線(不是但是,相反,編譯器可以很容易地確定它是否是一行。

程序確定這樣的小圖是否是循環的,或者它是否是一行,這並不需要花費太多時間,這是編譯器所做的。 因此,編譯器不會進入無限循環,並且JVM永遠不會耗盡堆棧空間,因為1)編譯器既不在JVM上運行,也不會在JVM上執行(因為沒有任何東西可以編譯而且編譯器永遠不會調用在這種情況下,JVM無論如何。)

我不知道有任何語言允許這樣的循環繼承圖(但我已經做了11年除了Java之外什么都沒做,所以我對除Java以外的任何東西的記憶都是糊塗的。)此外,我看不出這樣的用法。構造(在建模或現實生活中)。 不過,理論上可能很有趣。

編輯

好的,我運行了你的代碼,確實導致了堆棧溢出。 你是對的。 我將不得不坐下來真正研究這個以理解為什么編譯器允許這樣的構造。

很好找!!!!

如果我們更改它,您發布的示例可能會出現問題:

public class Outside {

    public class Inside extends Outside {

            public Inside(int val) {
        }

    }

    private Inside i;

    public Outside() {
        i = new Inside();
    }
}

但是,這是不是真的涉及到的事實, Inside是一個內部類的Outside ,它可能有獨立的頂級類相同的事。

您可以通過以下方式獲得答案:

Class.forName("MyClass");

這樣它就會得到解決但不會被實例化。 因此,如果解決方案本身導致崩潰,您可以查看。

我想這取決於你使用的JVM。

當我嘗試編譯時:

class A extends A {
}

我明白了:

$ javac A.java
A.java:1: cyclic inheritance involving A
class A extends A {
^
1 error

所以Java不會讓你做這種事情。 有關信息, java version "1.6.0_24"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM