为什么在实例初始值设定项内不允许递增(`x ++;`)尚未声明的字段,但是如果将其包装到匿名类中就可以了吗?

Cod*_*ete 2 java constructor field initializer anonymous-class

我很困惑,为什么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!    

}
Run Code Online (Sandbox Code Playgroud)

rge*_*man 6

在JLS,第8.3.3节,给出给人一种编译器错误前向参照的规则。

对于以简单名称引用f在class中声明的实例变量的情况C,如果发生以下情况,则是编译时错误:

  • 该引用显示在的实例变量初始化器C或C(§8.6)的实例初始化器中;和

  • 该引用出现在f自己声明器的初始化程序中或声明器左侧的一点处f;和

  • 该引用不在赋值表达式的左侧(第15.26节);和

  • 包含引用的最里面的类是C。

没有为来自嵌套类或内部类的引用提供编译器错误的规定。奇怪的是,非简单引用可以访问前向引用,例如

this.x++;
Run Code Online (Sandbox Code Playgroud)

另外,在同一部分的后面,有一个示例明确指出从其他类进行访问是可以的。

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;
}
Run Code Online (Sandbox Code Playgroud)

我只包含了相关部分-使用内部类进行正向引用的实例初始化器,最后加上了声明。