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).
|