|
Relates :
|
|
|
Relates :
|
|
|
Relates :
|
The following program doesn't compile (excerpt from Java Puzzlers - Puzzle 90 - 'it's absurd, it's pain, it's a superclass'):
public class Outer {
class Inner1 extends Outer {}
class Inner2 extends Inner1 {}
}
The program doesn't compile as the synthetic super call generated by javac inside Inner2's default constructor is:
this.super();
As a consequence the program is rejected with the following error:
Test.java:3: cannot reference this before supertype constructor has been called
class Inner2 extends Inner1 {}
^
This program would have compiled if javac were able to generate the following code:
Outer.this.super()
It's quite sensible not to consider the unqualified this as a suitable qualifier for a qualified super constructor call that has to be generated automatically by javac. Such a choice will always result in reference of 'this' before the superclass constructor has been called. However, this behaviour seems to be mandated by the JLS, section 8.8.7.1:
"Let C be the class being instantiated, let S be the direct superclass of C, and let i be the instance being created. The evaluation of an explicit constructor invocation proceeds as follows:
* First, if the constructor invocation statement is a superclass constructor invocation, then the immediately enclosing instance of i with respect to S (if any) must be determined. Whether or not i has an immediately enclosing instance with respect to S is determined by the superclass constructor invocation as follows:
o If S is not an inner class, or if the declaration of S occurs in a static context, no immediately enclosing instance of i with respect to S exists. A compile-time error occurs if the superclass constructor invocation is a qualified superclass constructor invocation.
o Otherwise:
+ If the superclass constructor invocation is qualified, then the Primary expression p immediately preceding ".super" is evaluated. If the primary expression evaluates to null, a NullPointerException is raised, and the superclass constructor invocation completes abruptly. Otherwise, the result of this evaluation is the immediately enclosing instance of i with respect to S. Let O be the immediately lexically enclosing class of S; it is a compile-time error if the type of p is not O or a subclass of O.
+ Otherwise:
# If S is a local class (��14.3), then let O be the innermost lexically enclosing class of S. Let n be an integer such that O is the nth lexically enclosing class of C. The immediately enclosing instance of i with respect to S is the nth lexically enclosing instance of this.
# Otherwise, S is an inner member class (��8.5). It is a compile-time error if S is not a member of a lexically enclosing class, or of a superclass or superinterface thereof. Let O be the innermost lexically enclosing class of which S is a member, and let n be an integer such that O is the nth lexically enclosing class of C. The immediately enclosing instance of i with respect to S is the nth lexically enclosing instance of this
[...] "
The last bullet explicitely states that, in this particular cases, javac should exploit the 0th-this as a qualifier for the super expression (this is because Inner2 is a subtype of Outer which encloses Inner1). I think that the lookup should start from the innermost lexically enclosing class of Inner2 (Outer) - thus skipping Inner2 completely. The change in the compiler to do so is quite trivial, and I think it would make the use of inner class more intuitive for the end-user.
This change seems also the only way for fixing a compiler regression bug (6541876) without restricting the space of the programs accepted by javac (e.g. fix for 4903103 should be invalidated if no JLS change is in sight).
|