繁体   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