Почему инкрементное (`x ++;`) пока не объявленное поле не разрешено внутри инициализатора экземпляра, но нормально, если оно помещено в анонимный класс? - PullRequest
2 голосов
/ 11 июля 2019

Я озадачен, почему добавление еще не объявленного поля (x++;) не разрешено внутри инициализатора экземпляра, но это становится разрешенным внутри инициализатора экземпляра, если он помещен в анонимный класс (да, анонимный класс имеет доступ к полям класса, нополе не инициализировано!).

class Test {

    { x++; }  // ERR: Cannot reference a field before it is defined

    Object anonFld = new Object() {     
        { x++; }     // fine! Sets x field below to 1 !

        void f() {
            x++; // fine!
        }
    };
    int x;

    // now x = 1     // anon constructor has set it!    

}

Ответы [ 2 ]

6 голосов
/ 11 июля 2019

JLS , раздел 8.3.3 , содержит правила выдачи ошибки компилятора для прямой ссылки.

Для ссылки простым именем на переменную экземпляра f, объявленную в классе C, это ошибка времени компиляции, если:

  • Ссылка появляется либо в инициализаторе переменной экземпляра C, либо в инициализаторе экземпляра C (§8.6); и

  • Ссылка появляется в инициализаторе собственного декларатора f или в точке слева от декларатора f; и

  • Ссылка не в левой части выражения присваивания (§15.26); и

  • Самый внутренний класс, включающий ссылку, C.

Нет условия для ошибки компилятора для ссылки из вложенного или внутреннего класса. Любопытно, что непростая ссылка может получить доступ к прямой ссылке, например,

this.x++;

Кроме того, позже в этом же разделе приведен пример, в котором явно говорится, что доступ из другого класса в порядке.

class UseBeforeDeclaration {
    // Snipped
    {
      // Snippped
        j = j + 1;
      // error - right hand side reads before declaration
      // Snipped
      Object o = new Object() { 
          void foo(){ j++; }
            // ok - occurs in a different class
          { j = j + 1; }
            // ok - occurs in a different class
      };
  }
  // Snipped
  int j;
}

Я включил только соответствующие части - инициализатор экземпляра, который делает прямую ссылку, используя внутренний класс, плюс объявление в конце.

0 голосов
/ 11 июля 2019

Компилятор компилирует внутренние классы после компиляции «основного» класса.Вот почему член x доступен во внутреннем классе, в то время как он не доступен в "основном" классе до его объявления.

...