Нечетная ситуация для «не может ссылаться на это до того, как конструктор супертипа был вызван»

Почему этот код не компилируется?

public class A { public class B extends A { public B(A a) { } } void foo() { A a = new A(); new B(a) { }; } } 

A.java:[7,17] cannot reference this before supertype constructor has been called

Компиляция успешна, если выполнено одно из этих изменений:

  • B является частным, а не общественным
  • строка 7 читает new B(A); вместо new B(A) { }

Использование версии javac: 1.6.0_20

Следует отметить, что Eclipse, javac и Intellij IDEA демонстрируют различия в поведении в отношении этих fragmentов. javac и поведение Java Puzzlers используются для справки в этом обсуждении.

Я смог вырезать fragment следующим образом:

 public class A { class B extends A { } void foo() { new B() { }; // DOES NOT COMPILE!! } } 

Этот сценарий обсуждается в Java Puzzlers , головоломка 90: это абсурд, это боль, это суперclass!

Ниже приведен fragment:

 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!! 

Проблема заключается в том, что суперclass Inner2 сам по себе является внутренним classом Inner1 , что делает Inner2 умолчанию Inner1 , поскольку для его создания требуется конструктор.

Метод «грубой силы» для устранения проблемы заключается в том, чтобы явно указать this выражение:

 // "brute-force" fix public class Outer { class Inner1 extends Outer { Inner1() { super(); } } class Inner2 extends Inner1 { Inner2() { Outer.this.super(); } } } // NOW COMPILES! 

Тем не менее, головоломка предписывает, что такую ​​сложную ситуацию лучше всего избегать в первую очередь. Вот некоторые цитаты:

Это компилируется, но оно бескомпромиссно сложное. Существует лучшее решение: всякий раз, когда вы пишете class-член, спросите себя: действительно ли этому classу нужен закрытый экземпляр? Если ответ отрицательный, сделайте его static . Иногда полезны внутренние classы, но они могут легко вводить осложнения, затрудняющие понимание программы. У них сложное взаимодействие с дженериками (головоломка 89), reflection (головоломка 80) и наследование (эта головоломка). Если вы объявите Inner1 static , проблема исчезнет. Если вы также объявляете Inner2 static , вы действительно можете понять, что делает программа: действительно хороший бонус.

Таким образом, для одного classа редко бывает как внутренним, так и подclassом другого. В более общем плане, редко бывает целесообразно распространять внутренний class; если вы должны, думать долго и упорно о вмещающих инстанции. Кроме того, предпочитайте static вложенные classы нестационарным. Большинство classов-членов могут и должны быть объявлены static .

Не знаете, в чем цель, но попробуйте это. Примечание. Я также вырезал прохождение A как аргумент как нестатические classы, с которыми они уже связаны. Я включил синтаксис для обращения к внешнему classу «this» для таких ситуаций, когда внутренний class мог скрыть внешнее поле / метод classа

 public class A { protected String field = "a"; public class B extends A { protected String field = "b"; public B() { System.out.println("" + A.this.field + " " + this.field); } @Override void foo() { System.out.println("b.foo()"); } } void foo() { A a = new A(); a.field = "a2"; B b = a.new B() { @Override void foo() { System.out.println("b.anon.foo()"); } }; b.foo(); } public static void main(String[] args) { new A().foo(); } } 

Выполнение этого будет выводиться:

 a2 b b.anon.foo() 

Надеюсь это поможет!

  • Как дождаться завершения всех задач в ThreadPoolExecutor, не закрывая Executor?
  • Android Telegram App -> java.lang.UnsatisfiedLinkError: не реализована реализация для void
  • Stream Live Android Audio на сервер
  • шифрование / дешифрование в Android с помощью AES
  • Как исправить INSTALL_PARSE_FAILED_MANIFEST_MALFORMED в приложении для Android
  • Как изменить цвет значка гамбургера в ящике для рисования материалов
  • В чем причина UnsupportedClassVersionError?
  • Драйвер не смог установить безопасное соединение с SQL Server с использованием шифрования Secure Sockets Layer (SSL)
  • Преобразование строк в дату mm / dd / yy до YYYY-MM-DD в java
  • Использование активности камеры в Android
  • Код Java для преобразования байта в шестнадцатеричный
  • Interesting Posts

    Как найти код обновления для установленного файла MSI?

    Установщик Emacs для Windows 8

    DataGridView с использованием SortableBindingList

    Spring-Data FETCH JOIN with Paging не работает

    Запуск приложения в GDB до тех пор, пока не произойдет исключение

    Если частные вспомогательные методы являются статическими, если они могут быть статическими

    Проблема с диалоговыми windowsми jQuery и плагинами Datepicker

    Приведение компонента к BufferedImage приводит к повреждению отображения

    Как отключить предупреждение, которое Chrome дает, если сертификат безопасности не доверен?

    Почему полиморфические значения не выводятся в Haskell?

    Неявные преобразования C ++

    Диспетчер задач показывает запущенные программы – как я могу увидеть те, которые были завершены?

    Массивы указателей функций в Фортране

    Каков самый быстрый способ конвертировать float в int на x86

    Изменение ViewPager для включения бесконечной прокрутки страницы

    Давайте будем гением компьютера.