Java:inheritanceself的类

我知道这是毫无意义的:我发现它很有趣,我想更多地询问当你创建一个inheritance自身的类时会发生什么的机制,导致堆栈溢出崩溃。 令人惊讶的是,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 // ... } } 

在最终forms中,这个问题与循环inheritance和内部类无关。 它只是由未绑定的递归构造函数调用引起的无限递归。 通过以下简单示例可以显示相同的效果:

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

请注意,此代码完全有效,因为Java不对递归调用应用任何限制。

在你的情况下,由于inheritance,它稍微复杂一些,但如果你还记得子类的构造函数隐式调用了超类的构造函数,那么应该很清楚这些调用会形成无限递归。

尝试像eclipse这样的IDE,它不允许你这样做。 即给出这样的错误。

检测到周期:类型Test无法扩展/实现自身或其自己的成员类型之一

如果我们更改它,您发布的示例可能会出现问题:

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

但这与InsideInside的内部类的事实并没有关系,它可能与单独的顶级类相同。

尝试进入循环inheritance链时,java编译器不会进入无限循环。 毕竟,每个inheritance链都是最终有限的图形(并且从计算上讲,它具有非常少量的节点和边缘。)更确切地说,从子类A到(最终)超类Z的inheritance图必须是一条线(不是但是,相反,编译器可以很容易地确定它是否是一行。

程序确定这样的小图是否是循环的,或者它是否是一行,这并不需要花费太多时间,这就是编译器的作用。 因此,编译器不会进入无限循环,并且JVM永远不会耗尽堆栈空间,因为1)编译器既不在JVM上运行,也不会在JVM上执行(因为没有任何东西可以编译,编译器也不会调用在这种条件下JVM无论如何。)

我不知道任何允许这种循环inheritance图的语言(但我已经做了11年除了Java之外什么都没做,所以我对Java以外的任何东西的记忆都是糊涂的。)此外,我看不出这样的用法。构造(在建模或现实生活中)。 不过,理论上可能很有趣。

编辑

好的,我运行了你的代码,确实导致了堆栈溢出。 你是对的。 我将不得不坐下来真正研究这个以理解为什么编译器允许这样的构造。

很好找!!!!

扩展自己会产生循环inheritance错误(java不允许)。 您的代码示例已编译并且有效。


由于弗拉基米尔·伊万诺夫的坚持,我将修复我的编辑。

由于以下原因,您的代码会抛出StackOverflowError

 Inside o = new Inside(0); 

由于Inside扩展OutsideInside首先隐式调用super()方法(因为你自己没有调用它)。 Outside()构造函数初始化Inside o并且循环再次运行,直到堆栈已满且溢出(堆栈Inside和内部的InsideOutside太多)。

希望这有助于弗拉基米尔伊万诺夫。

您可以通过以下方式获得答案:

 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"