Java 为什么不是';静态初始化块中是否允许限定的静态最终变量? 案例1 案例2

Java 为什么不是';静态初始化块中是否允许限定的静态最终变量? 案例1 案例2,java,static,final,static-initialization,qualified-name,Java,Static,Final,Static Initialization,Qualified Name,为什么案例1会导致编译错误?JLS持有答案(请注意粗体陈述): 同样,每个空白的最终变量最多只能分配一次;当对它进行赋值时,它必须绝对未赋值当且仅当变量的简单名称(或者,对于字段,其由该名称限定的简单名称)出现在赋值运算符的左侧时,此类赋值才会发生。[] 这意味着在分配静态最终变量时必须使用“简单名称”——即不带任何限定符的var名称。显然,这是一种廉价的语法技巧,用于限制类本身内的确定(非)分配分析 如果字段在语法上用类名限定,则代码通常位于另一个类中,分析无法到达该类 在你的例子中,这个技巧

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

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

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


这意味着在分配静态最终变量时必须使用“简单名称”——即不带任何限定符的var名称。

显然,这是一种廉价的语法技巧,用于限制类本身内的确定(非)分配分析

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

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

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

如果他们有更多的资源,他们可能会制定更好的规则。但我们现在无法更改规格。

案例2有效,那么为什么要在意呢?它显然看起来像是进入外国决赛(这是非法的)。这是一个非常棘手的好问题,现在就让大脑工作吧……)@RohitJain说实话,我不认为这是一个很好的面试问题:你不能根据程序员是否知道这个问题的答案来得出任何结论!这是我听过的最没用的问题之一:)我不明白为什么ppl试图让程序员变成编译器。我最好问一下平衡搜索树和Bloom过滤器:)@djechlin-基本原理是1)这简化了规范,2)ThisClass.someFinal=valuesomeFinal=value,code>是一个模糊且不必要的替代方案;i、 e.不需要支持它。@编码人员在所有初始化完成之前,该类的名称不可用,因此在静态初始化器完成之前,程序(该名称)不存在。@xagyg。。恐怕这不是原因。类始终首先加载,然后进行初始化过程。静态变量仅附加到类,因此不能使用
类名
是没有意义的。你可以在实践中看到这一点。只要从变量中删除
final
关键字,第一个代码就可以编译了。@StephenC:这实际上使规范复杂化,因为它是静态变量的一般访问规则中的一个例外。如果没有这一特殊规则,粗体的句子本可以省略。我认为这样做的理由可能是,它只是在早期的编译器中以这种方式实现,然后被纳入规范。在语言规范的后续版本中,有一些其他规则明确定义了编译器存在的稍微客观的行为是正确的。很抱歉,来晚了,但我认为该代码根本没有违反JLS的这一点。JLS的引文只是说
Program.var=8
不是“这样的赋值”,即需要首先明确取消赋值的赋值类型。我认为规范可以更改而不会引起问题,因为允许
Program.var
不会使任何当前有效的程序代码无效,例如,这是一个兼容的更改,还是我错了?:-D没问题,只是觉得我遗漏了一些东西。。。谢谢你的回答@siegi:扩展编译器接受的程序类将增加已部署代码的数量,这在较旧的编译器安装中是不可用的。如果已部署的代码在旧编译器上无法工作,因为它使用了旧编译器不理解的有价值的新语言特性,那么这是一个可接受的权衡,这是一个权衡。允许新的语法形式而没有主要优势,会给旧安装的所有者带来成本,但回报很小。@supercat:当然你是对的,在没有太多好处的情况下改变语言是不好的。另一方面:如果语言变化与一个新的主要版本(如Java 6到Java 7)同时发生,那么无论如何,你都需要一个新的编译器和运行时环境,至少如果你想使用任何新特性或为新版本编译的任何库……这里可怕的事情是,如果你添加
System.out.println(a.a)
a=1中插入一个
main
,它将实际访问并打印出0,然后是1:Youch。在终值之前观察终值。
class Program {
    static final int var;

    static {
        var = 8;  //OK
    }

    public static void main(String[] args) {
        System.out.println(Program.var);
    }
}
static class A
{
    static final int a;
    static
    {
        // System.out.println(a); // illegal
        System.out.println(A.a);  // compiles!
        a = 1;
    }
}