开发者

Java : Class inheriting self

I know this is pointless: I just find it funny and I want to inquire more about the mechanics of what happens when you create a class that inherits itself, resulting in a stack overflow crash. It's amazing that Java allows you to make such a construct to begin with.

I am just guessing, but is the JVM putting itself into an infinite loop trying to resolve the class before instancing it, or is it actually instancing multiple copies of the class endlessly?

I should have been more specific; I am using an inner class to derive fro开发者_运维技巧m enclosing class.

 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();
    }
}


Remember that, since Inside extends Outside, it has an implicit call to super() which is the constructor of Outside (which in turn calls the constructor of Inside) and so it goes around.

The code you posted is conceptually not different from the following program:

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
                 //   ...
    }
}


In its final form this problem has nothing to do with cyclic inheritance and inner classes. It's just an infinite recursion caused by unbound recursive constructor call. The same effect can be shown by the following simple example:

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

Note that this code is perfectly valid, since Java doesn't apply any restrictions on recursive calls.

In your case it's slightly more complicated due to inheritance, but if you recall that constructor of subclass implicitly call a constructor of superclass, it should be clear that these calls form infinite recursion.


Try in an IDE like eclipse, it wont allow you to do so. ie gives an error like this.

Cycle detected: the type Test cannot extend/implement itself or one of its own member types


The example you posted could get problematic if we change it a bit more:

public class Outside {

    public class Inside extends Outside {

            public Inside(int val) {
        }

    }

    private Inside i;

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

But this is not really related to the fact that Inside is an inner class of Outside, it could have happened with separate top-level-classes identically.


The java compiler is not going to enter into an infinite loop when trying to enter a cyclic inheritance chain. After all, every inheritance chain is a eventually finite graph (and, computationally speaking, with a very small number of nodes and edges.) More precisely, the inheritance graph from subclass A to (eventual) superclass Z must be a line (not the other way around, though), and the compiler can easily determine if it is a line or not.

It does not take much for a program to determine if such a small graph is cyclic or not, or if it is a line or not, which is what the compiler does. So the compiler does not go into an infinite loop, and the JVM never runs out of stack space since 1) neither the compiler runs on the JVM, nor 2) the JVM get to executes (since nothing gets to compile and the compiler never invokes under such conditions the JVM anyways.)

I'm not aware of any languages that permit such cyclic inheritance graphs (but I've been doing nothing but Java for 11 years, so my memory of anything other than Java is mushy.) I cannot see, furthermore, the use of such a construct (in modeling or real life). Might be theoretically interesting, though.

edit

Ok, I ran your code and indeed it causes an stack overflow. You were right. I'm gonna have to sit and really study this to understand why the compiler allows such a construct.

Nice find!!!!


Extending oneself generates an error of cyclic inheritance (which java doesn't allow). Your code sample does compile and is valid.


Due to Vladimir Ivanov's persistence, I will fix my edit.

Your code throws a StackOverflowError because of the following.

Inside o = new Inside(0);

Since Inside extends Outside, Inside first calls the super() method implicitly (since you've not called it yourself). Outside() constructor initializes Inside o and the cycle runs again, until the stack is full and it overflow (there's too many Inside and Outside inside the heap stack).

Hope this helps especially Vladimir Ivanov.


You can get the answer by:

Class.forName("MyClass");

This way it gets resolved but not instantiated. So you can chack if resolution itself causes the crash.

I guess it depends on the JVM you use.


When I try to compile :

class A extends A {
}

I get :

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

So Java don't let you do this kind of thing. For information, java version "1.6.0_24"

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜