Hierarchy of inner classes in Java
I am using a hierarchy of inner classes to represent some data in a开发者_开发技巧n application and I have run into an error message that I simply do not understand. My code can be boiled down to the following minimal example:
public class A {
public class B extends A {}
public class C extends B {}
}
Javac (and my IDE of course) fails to compile the code with the following error message:
A.java:3: cannot reference this before supertype constructor has been called
public class C extends B {}
^
1 error
I didn't write this
anywhere. There is no more code than provided above, so I assume javac has generated something related to the inner class.
I have found another way to represent my data, so I am simply interested in a good explanation of why it doesn't compile.
You need an outer class instance to create an inner class instance i.e something like new Outer().new Inner();
To extend the inner class (Parent inner class) with another inner class (child inner class), you cannot call the constructor of 'parent inner class' because the instance of 'outer class' is not there.
Try like this,
public class A{
public class B extends A {
B() { }
}
public class C extends B {
C() {
new A().super();
}
}
public static void main(String args[]) {
}
}
Similar question : Odd situation for “cannot reference this before supertype constructor has been called”
The other poster is correct, but how to fix? Simply make your class static
:
public class A {
public static class B extends A {}
public static class C extends B {}
}
Note that if your inner classes refer to fields of the outer class, you can't make them static, otherwise you can (and should - doing so reduces dependencies).
Your code compiles under Java 7.
The following workaround compiles under Java 6.
public class C extends B
{
public C()
{
A.this.super();
}
}
@saugok's link to the previous question quoted Joshua's explanation. Basically he argued that since C is subclass of A, C inherits A's members as C's members. Therefore B is also C's member. (For example a class literal C.B.class
is valid.) Therefore he argues that C.this
is the enclosing instance for B's super()
, therefore C(){super();}
is actually C(){C.this.super();}
. Since C.this
cannot be evaluated before super constructor, thus the error.
However this doesn't seem to be warranted by the language spec. See #8.1.3. Since B
is not immediately lexically enclosed by C
, B
is not a direct inner class of C
, there is no reason to say that B
's direct enclosing instance must be an instance of C
.
We need to pass B()
an instance of A
. It is true that C.this
is an instance of A
( try this code: new C().new B().new C().new B();
) therefore it could be a candidate. There is also another candidate, A.this
. A.this
is available and ready to use (it's passed in as the hidden parameter to C()
).
According to javap
, javac 7 compiles the code into
class B
private A this$0;
B( A a )
this$0 = a;
super(); // A()
class C extends B
private A this$0;
C( A a )
this$0 = a;
super( a ); // B(A)
精彩评论