Ответ 1
Следует отметить, что Eclipse,
javac
и Intellij IDEA демонстрируют различия в поведении в отношении этих фрагментов.javac
и поведение Java Puzzlers используется для справки в этом обсуждении.
Мне удалось вырезать фрагмент следующим образом:
public class A {
class B extends A {
}
void foo() {
new B() { }; // DOES NOT COMPILE!!
}
}
Этот сценарий обсуждается в Java Puzzlers, головоломка 90: это абсурд, это боль, это суперкласс!
Ниже приведен фрагмент:
public class Outer { // "A"
class Inner1 extends Outer {} // "B"
class Inner2 extends Inner1 {} // "B" anonymous
}
// DOES NOT COMPILE!!
Проблема заключается в том, что из-за того, как определяется конструктор по умолчанию, мы действительно имеем следующее:
// 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!!
Проблема заключается в том, что суперкасс Inner2
сам является внутренним классом Inner1
, тем самым делая конструктор по умолчанию Inner2
по умолчанию, поскольку он требует, чтобы экземпляр-экземпляр был предоставлен конструктору.
Метод "грубой силы" для исправления проблемы заключается в том, чтобы явно предоставить это выражение с выражением this
:
// "brute-force" fix
public class Outer {
class Inner1 extends Outer {
Inner1() { super(); }
}
class Inner2 extends Inner1 {
Inner2() { Outer.this.super(); }
}
}
// NOW COMPILES!
Однако, головоломка предписывает, что такую сложную ситуацию лучше всего избегать в первую очередь. Вот несколько цитат:
Это компилируется, но он бескомпромиссно сложный. Существует лучшее решение: всякий раз, когда вы пишете класс-член, спросите себя: действительно ли этому классу нужен закрытый экземпляр? Если ответ отрицательный, сделайте его
static
. Иногда полезны внутренние классы, но они могут легко вводить осложнения, затрудняющие понимание программы. У них сложное взаимодействие с дженериками (головоломка 89), отражение (головоломка 80) и наследование (эта головоломка). Если вы объявитеInner1
равнымstatic
, проблема исчезнет. Если вы также объявляетеInner2
static
, вы действительно можете понять, что делает программа: действительно хороший бонус.Таким образом, для одного класса редко бывает как внутренним, так и подклассом другого. В более общем плане, редко бывает целесообразно распространять внутренний класс; если вы должны, думать долго и упорно о вмещающих инстанции. Кроме того, предпочитайте
static
вложенные классы неstatic
. Большинство классов-членов могут и должны быть объявленыstatic
.