【问题标题】:Why does static field self assignment compile only with explicit static syntax?为什么静态字段自赋值只能使用显式静态语法编译?
【发布时间】:2018-01-08 20:47:15
【问题描述】:

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

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);
    }
}

【问题讨论】:

  • 因为规范就是这样写的。 Sec 8.3.3,确切地说。具体来说,这不是一个简单的名称,因此并非所有编译时错误的条件都得到满足。
  • 出于好奇:这种事情的 IRL 用例是什么?真正的程序员原则:难写,就应该难读? ;-)
  • @AndyTurner 检查了您的参考资料,对我来说看起来是正确的。如果你把它放在一个答案中,我会接受它。
  • @Lothar:这只是一个安全网,还有其他漏洞(例如来自方法或其他类的引用)。让不寻常的语法成为逃生口是一种非常常见的方法。
  • @Lothar - 这是一个反问......

标签: java static initialization


【解决方案1】:

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

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

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

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

强调我的。

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

【讨论】:

  • 有一件事困扰着我。类变量的声明在使用后并没有真正到来。它与它在同一行中。
  • @user889742 措辞已在 JLS 9 中更新。我已在此处更新。
  • 这些规则旨在避免常见的 use-before-initialization 错误。 <classname>.<staticname> 语法允许程序员在复杂情况下说“我知道我在做什么”;例如存在不可避免的循环初始化依赖关系。
【解决方案2】:

除了@Andy 的回答,我还想展示一些取自 JLS chapter 的示例。他们解释了Use Before Declaration规则,展示了有效和无效的情况:

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) {
        // ...
    }
}

【讨论】:

  • 不以任何方式回答问题。
  • 您的编辑也没有。您只是更新了答案以重复 OP 的观察。关于字节码的答案不可能是关于编译错误的问题的答案。问题是为什么编译错误。
  • @EJP 我添加了来自 JLS 的多个有趣的代码示例,除了 Andy 的回答之外,这些示例还有助于理解行为。
猜你喜欢
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 2016-08-31
  • 2017-12-08
  • 1970-01-01
  • 1970-01-01
  • 2011-01-18
  • 2014-04-20
相关资源
最近更新 更多