Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:类继承自组织_Java_Oop_Inheritance - Fatal编程技术网

Java:类继承自组织

Java:类继承自组织,java,oop,inheritance,Java,Oop,Inheritance,我知道这是毫无意义的:我只是觉得这很有趣,我想进一步了解创建继承自身的类时会发生什么,从而导致堆栈溢出崩溃。令人惊讶的是,Java允许您从一开始就创建这样的构造 我只是在猜测,但是JVM是将自己放入一个无限循环中,试图在实例化类之前解析该类,还是实际上无限地实例化该类的多个副本 我应该说得更具体些;我使用一个内部类从封闭类派生 public class Outside { private int outsideValue; public class Inside extend

我知道这是毫无意义的:我只是觉得这很有趣,我想进一步了解创建继承自身的类时会发生什么,从而导致堆栈溢出崩溃。令人惊讶的是,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();
    }
}

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

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,这个节目没有什么特别之处。堆栈溢出是由于两个相互递归的构造函数造成的。看看我的答案,我想出来了。。。把我抓走了