为什么静态字段自我赋值仅使用显式静态语法进行编译?

时间:2018-01-08 20:47:16

标签: java static initialization

为什么这个代码在右侧使用显式静态字段表示法编译,但不是没有?

public class A
{
    static int a = ++A.a;  // compiles
    //static int a = ++a;  // error - cannot reference a field before it is defined

    public static void main(String[] args) {
        System.out.println(a);
    }
}

2 个答案:

答案 0 :(得分:4)

这就是语言规范的编写方式。具体来说,Sec 8.3.3说:

  

对字段的引用有时会受到限制,即使字段在范围内也是如此。以下规则约束对字段的前向引用(在文本上使用字段声明之前)以及自引用(字段在其自己的初始化程序中使用)。

     

对于对简单名称的引用,对类中声明的类变量f   或接口C,如果

,则编译时错误      
      
  • ...
  •   

强调我的。

A.a不是一个简单的名称,因此它不是编译时错误。

答案 1 :(得分:1)

除了@Andy的回答,我想展示一些从这个JLS chapter中获取的例子。他们解释了使用前宣言规则,展示了有效的&无效案件:

class UseBeforeDeclaration {
    static {
        int a = UseBeforeDeclaration.b + 2; // ok - 'b' is not accessed via simple name
    }

    {
        c = 1000000; // ok - assignment    
        c = c + 100; // error - right hand side reads before declaration    
        int d = c++; // error - read before declaration    
        int e = this.c * 2; // ok - 'c' is not accessed via simple name
    }

    static int b;    
    int c;
}

此外,在对有效static int a = ++A.a行进行字节码调查之后,我们可以看到它被编译成:

static <clinit>()V
  L0
    LINENUMBER 4 L0
    GETSTATIC src/java/A.a : I
    ICONST_1
    IADD
    DUP
    PUTSTATIC src/java/A.a : I
    PUTSTATIC src/java/A.a : I
    RETURN

相当于:

public class A {
    static int a;

    static {
        ++a;
    }

    public static void main(String[] args) {
        // ...
    }
}