St.Antario
St.Antario

Reputation: 27425

Inconsistent class hierarchy

I've read about class constructor here and a question then arises as to why does the following hierachy is incorrect:

public class Test extends Subclass.Inner{ //compile-time error 
                           //The hierarchy of the type Test is inconsistent
    public Test() {
        super();
    }
}


public class Subclass extends Test{
    public class Inner{
    }
}

Formally

If a superclass constructor invocation statement is unqualified, and if S is an inner member class, then it is a compile-time error if S is not a member of a lexically enclosing class of C by declaration or inheritance.

I thought the example completely satisfies the rule I cited. In the case SubClass is lexically inclosing class for Test by inheritance. Why doesn't the code work fine? Could you provide an appropriate example reflecting that?

Upvotes: 4

Views: 312

Answers (3)

Radiodef
Radiodef

Reputation: 37855

Here is a clause you are missing (8.4.1):

A class C directly depends on a type T if T is mentioned in the extends or implements clause of C either as a superclass or superinterface, or as a qualifier of a superclass or superinterface name.

A class C depends on a reference type T if any of the following conditions hold:

  • C directly depends on a class D that depends on T (using this definition recursively).

It is a compile-time error if a class depends on itself.

It is a compile-time error because the declaration of a superclass of Subclass contains Subclass as a qualifier of a superclass name.

That is besides the extremely weird circular definition you have going here. Test would be an outer scope of itself.

This doesn't compile either, though it's not as puzzling as the inner class:

class Test implements Test.ITest {
    interface ITest {}
}

Netbeans gives me a more straightforward error that there is 'cyclic inheritance'. A class declaration is not allowed to reference itself in this manner.

Upvotes: 1

TimePath
TimePath

Reputation: 54

Inner instance classes (non-static) are actually transformed like so:

public class Subclass extends Test {
    public class Inner {
    }
}

becomes something like this:

public class Subclass extends Test {

}

public class Inner {
    Subclass parent;
    public Inner(Subclass parent) {
        this.parent = parent;
    }
}

The following is valid:

public class Container extends Subclass {
    public class Test extends Subclass.Inner {
        public Test() {
            super();
        }
    }
}

public class Subclass {
    public class Inner {
    }
}

Upvotes: 2

Eran
Eran

Reputation: 393936

An instance of an inner class must have an enclosing instance, which gets initialized before the inner class instance. On the other hand, a super class constructor is always executed before a sub-class constructor. Therefore, creating an instance of SubClass requires calling first the constructor of Test, which requires calling first the constructor of SubClass.Inner, but SubClass.Inner cannot be initialized before its containing instance.

I believe that in order to satisfy the condition you quoted, the super class Inner must be enclosed by a super class of Test. In your case it is enclosed by a sub-class of Test.

Upvotes: 2

Related Questions