是'错误:变量a可能没有被初始化'在这个if构造中真的有必要吗?

rah*_*ahs 2 java if-statement

我如何告诉Java我不需要初始化a以获得有效的程序并且不给我错误?

int a;
boolean b = true;
while (true) {
   if (b == false) {
       System.out.print(a);
       break;
   } else {
       b = false;
       a = 5;
   }
}
Run Code Online (Sandbox Code Playgroud)

如果我不能,那么为什么这就是编译器的设计方式?

是否容易设计这样的编译器,或者这是一种确保我重构代码的机制?

这是不一样的问题,这一个

Ste*_*n C 10

是'错误:变量a可能没有被初始化'在这个if构造中真的有必要吗?

是的,这是必要的.Java语言规范需要它.这在JLS 16 - Definite Assignment中有所介绍.

"当对其值进行任何访问时,每个局部变量(第14.4节)和每个空白最终字段(第4.14.4节,第8.3.1.2节)必须具有明确赋值."


我如何告诉Java我不需要初始化a以获得有效的程序并且不给我错误?

你无法告诉Java.您需要初始化变量...或重构代码.


如果我不能,那么为什么这就是编译器的设计方式?

因为Java编译器必须实现规范,否则它不是一个合适的Java编译器.规范说这是一个错误.

真正的问题是规范说明的原因.答案是,编译器编写者不必在所有Java编译器中包含困难的定理证明代码.

  • 在您给出的示例中,程序员很明显该变量将始终被初始化.但是,编译器需要验证它.它需要绝对确定,因为未初始化的变量将具有未定义的行为.

  • 自动(无向)验证是一项复杂的任务.复杂意味着要编写更多(编译器)代码,更多(编译器)错误等等.

  • 这项技术的"最新技术"并不适合对复杂的Java代码进行这种分析.

  • 存在(理论上)情况,其中验证变量被初始化在数学上是不可能的.

所以...明智地......指定Java语言的人将其推回给程序员.根据JLS中规定的规则,您需要编写代码,以便在使用前明确分配变量.

还有第二个原因.假设JLS确实允许Java编译器接受

   System.out.print(a);
Run Code Online (Sandbox Code Playgroud)

当且仅当它能够满足自己a以前(始终)先前已初始化.现在考虑由不同的人(或不同时间的同一个人)编写的两个Java编译器来实现相同版本的JLS.

  • 编译器C1可以确定a总是初始化,并说该程序是有效的.

  • 编译器C2无法弄清楚a总是初始化,并说该程序无效.

我们现在有两个表面上实现相同版本JLS的Java编译器,但不同意您的示例程序(上面)是否有效.这根本站不住脚.


为了进一步复杂化,我怀疑当JVM验证刚刚加载的字节码时,也必须发生类似于"明确赋值"检查的内容.因此,对JLS明确赋值规则的更改将会影响到JVMS,并可能影响JVM平台对其他编程语言和直接编译/生成JVM字节码的工具的行为.