为什么静态初始化块中不允许使用合格的静态最终变量?

Rav*_*avi 52 java static final qualified-name static-initialization

情况1

class Program {
    static final int var;

    static {
        Program.var = 8;  // Compilation error
    }

    public static void main(String[] args) {
        int i;
        i = Program.var;
        System.out.println(Program.var);
    }
}
Run Code Online (Sandbox Code Playgroud)

案例2

class Program {
    static final int var;

    static {
        var = 8;  //OK
    }

    public static void main(String[] args) {
        System.out.println(Program.var);
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么案例1会导致编译错误?

ars*_*jii 43

JLS持有答案(注意粗体陈述):

同样,每个空白的最终变量最多只能分配一次; 当它的赋值发生时,它必须是绝对未分配的.当且仅当变量的简单名称(或者,对于字段,其由此限定的简单名称)出现在赋值运算符的左侧时,才会定义此类赋值.[ §16 ]

这意味着在分配静态最终变量时必须使用"简单名称" - 即没有任何限定符的var名称.

  • @djechlin - 基本原理是1)这简化了规范和2)`ThisClass.someFinal = value;`是`someFinal = value;`的一个模糊和不必要的选择; 即没有*需要*来支持它. (7认同)
  • @xagyg ..我担心这不是原因.始终首先加载类,然后进行初始化过程.静态变量只附加到类,因此我们不能使用`class name`是没有意义的.你可以在实践中看到它.只需从变量中删除`final`关键字,第一个代码就可以正常编译. (7认同)
  • @coders在完成所有初始化之前,该类无法按名称提供,因此在静态初始化程序完成之前,Program(按名称)不存在. (5认同)
  • @StephenC:它实际上使规范复杂化,因为它是静态变量的一般访问规则的例外.如果没有这个特殊规则,可以省略粗体句子.我假设这个的基本原理可能是它只是在早期的编译器中以这种方式实现,然后使其成为规范.在语言规范的更高版本中还有一些其他规则,其中编译器的现有略微不明确的行为被明确定义为正确的. (5认同)
  • 理由是什么? (2认同)

irr*_*ble 7

显然,这是一种廉价的句法技巧,可以限制类本身内的明确(非)赋值分析.

如果字段在语法上使用类名限定,则代码通常位于另一个类中,而分析无法到达.

这个技巧在你的例子中失败了.奇怪的其他例子:

static class A
{
    static final int a;
    static
    {
        // System.out.println(a); // illegal
        System.out.println(A.a);  // compiles!
        a = 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果他们有更多的资源,他们可能会做出更好的规则.但我们现在无法改变规格.

  • 好吧,我认为spec _could_可以在不引起问题的情况下进行更改,因为允许`Program.var`不会使任何当前有效的程序代码无效,即它是兼容的更改,或者我错了? (2认同)