Odd situation for "cannot reference this before supertype constructor has been called"
It should be noted that Eclipse, javac
, and Intellij IDEA exhibit differences in behaviors with regards to these snippets. javac
and the Java Puzzlers behavior is used for reference in this discussion.
I was able to cut down the snippet to the following:
public class A {
class B extends A {
}
void foo() {
new B() { }; // DOES NOT COMPILE!!
}
}
This scenario is discussed in Java Puzzlers, Puzzle 90: It's Absurd, It's a Pain, It's Superclass!
The snippet given is the following:
public class Outer { // "A"
class Inner1 extends Outer {} // "B"
class Inner2 extends Inner1 {} // "B" anonymous
}
// DOES NOT COMPILE!!
The problem is that due to how default constructor is defined, we really have the following:
// Same as above but with default constructor included explicitly
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { super(); }
}
}
// STILL DOES NOT COMPILE!!
The problem is that Inner2
's superclass is itself an inner class Inner1
, thus making Inner2
's default constructor illegal since it requires an enclosing instance to be supplied to the constructor.
The "brute-force" way to fix the problem is to provide this explicitly with a qualified-this
expression:
// "brute-force" fix
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { Outer.this.super(); }
}
}
// NOW COMPILES!
However, the puzzle prescribes that such complicated situation is best avoided in the first place. Here are some quotes:
This compiles, but it is mind-numbingly complex. There is a better solution: Whenever you write a member class, ask yourself, Does this class really need an enclosing instance? If the answer is no, make it
static
. Inner classes are sometimes useful, but they can easily introduce complications that make a program difficult to understand. They have complex interactions with generics (Puzzle 89), reflection (Puzzle 80), and inheritance (this puzzle). If you declareInner1
to bestatic
, the problem goes away. If you also declareInner2
to bestatic
, you can actually understand what the program does: a nice bonus indeed.In summary, it is rarely appropriate for one class to be both an inner class and a subclass of another. More generally, it is rarely appropriate to extend an inner class; if you must, think long and hard about the enclosing instance. Also, prefer
static
nested classes to non-static
. Most member classes can and should be declaredstatic
.