Java:类继承自组织
我知道这是毫无意义的:我只是觉得这很有趣,我想进一步了解创建继承自身的类时会发生什么,从而导致堆栈溢出崩溃。令人惊讶的是,Java允许您从一开始就创建这样的构造 我只是在猜测,但是JVM是将自己放入一个无限循环中,试图在实例化类之前解析该类,还是实际上无限地实例化该类的多个副本 我应该说得更具体些;我使用一个内部类从封闭类派生Java:类继承自组织,java,oop,inheritance,Java,Oop,Inheritance,我知道这是毫无意义的:我只是觉得这很有趣,我想进一步了解创建继承自身的类时会发生什么,从而导致堆栈溢出崩溃。令人惊讶的是,Java允许您从一开始就创建这样的构造 我只是在猜测,但是JVM是将自己放入一个无限循环中,试图在实例化类之前解析该类,还是实际上无限地实例化该类的多个副本 我应该说得更具体些;我使用一个内部类从封闭类派生 public class Outside { private int outsideValue; public class Inside extend
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();
}
}
您可以通过以下方式获得答案:
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版本“1.6.0\u24”
请尝试在类似eclipse的IDE中使用,它不允许您这样做。ie给出了这样一个错误
检测到循环:类型测试无法扩展/实现自身或自己的成员类型之一扩展自身会生成循环继承错误(java不允许)。您的代码示例可以编译并且是有效的
由于持久性,我将修复我的编辑 由于以下原因,您的代码会抛出一个
堆栈溢出错误
Inside o = new Inside(0);
由于内部
扩展了外部
,内部
首先隐式调用super()Outside()
构造函数初始化内部o
并再次运行循环,直到堆栈已满并溢出(堆堆栈内部和外部过多)
希望这对Vladimir Ivanov特别有帮助。请记住,由于内部扩展了外部,因此它有一个隐式调用super()
,它是外部的构造函数(反过来又调用内部的构造函数),因此它是循环的
从概念上讲,您发布的代码与以下程序没有区别:
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
// ...
}
}
java编译器在尝试进入循环继承链时不会进入无限循环。毕竟,每个继承链都是一个最终有限图(从计算上讲,节点和边的数量非常少)。更准确地说,从子类a到(最终)超类Z的继承图必须是一条线(但不是相反),编译器可以轻松地确定它是否是一条线
对于一个程序来说,判断这样一个小图是否是循环的,或者它是否是一条直线并不需要太多的时间,这就是编译器所做的。因此编译器不会进入无限循环,JVM也不会耗尽堆栈空间,因为1)编译器不会在JVM上运行,2)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();
}
}
但这与内部
是外部
的一个内部类这一事实并没有真正的关系,它可能发生在不同的顶级类中。在其最终形式中,这个问题与循环继承和内部类无关。它只是由未绑定的递归构造函数调用引起的无限递归。通过以下简单示例可以显示相同的效果:
public class A {
public A() {
new A();
}
}
请注意,这段代码是完全有效的,因为Java对递归调用没有任何限制
在您的例子中,由于继承,它稍微复杂一些,但是如果您回忆起子类的构造函数隐式调用了超类的构造函数,应该很清楚这些调用形成了无限递归。@Turtleteos那么,当您尝试这样做时,实际发生了什么?您的意思是什么?我无法获得任何循环继承,您使用的是哪个版本?java:1:涉及first的循环继承尝试继承正在声明的类会导致编译错误(Windows/Cygwin上的JDK1.6)。您使用的是什么版本的Java?使用内部类继承外部类javac
并不是创建类文件的唯一方法。你也可以编辑一个类来获得一个伪类。运行我发布的代码,你会得到一个堆栈溢出错误。创建另一个类并尝试引用外部类。这不是关于循环继承(-1)。这是关于内部类继承的问题。@Vladimir我的答案是在问题添加代码之前写的。如果没有代码,就无法知道op谈论的是内部类(“你创建了一个继承自己的类”这正是我所做的)。@Krtel,如果答案再次编辑,我会收回我的反对票。这不是循环继承(-1)@Vladimir Ivanov,op后来添加了代码,因此我添加了第二句。是的。这不是我的愿望。仅供参考,所以不允许您更改投票,直到答案被编辑。谢谢。。。我只是坐在这里东张西望想把东西弄碎broke@luis.espinal,这个节目没有什么特别之处。堆栈溢出是由于两个相互递归的构造函数造成的。看看我的答案,我想出来了。。。把我抓走了