【问题标题】:Why doesn't the java compiler recognise fields have been initialized?java编译器为什么不能识别字段已经初始化?
【发布时间】:2017-10-12 17:16:58
【问题描述】:

假设我有以下代码

int myVar;
final boolean condition = <someCondition>;
if (condition) {
   myVar = 1;
}
if (condition) {
   System.out.println("myVar = " + myVar);
}

当我编译这个时,我得到了预期的myVar might not have been initialized 错误。 这是编译器中的错误吗?很容易看出“myVar”是在condition 为真时设置的,并且仅在condition 为真时才被引用。 (condition 也永远不会重置)

P.S:对于那些需要将其初始化为 0 的 cmets,是的,我知道这一点。但关键是,我希望“myVar”是最终的(即,最多设置一次值)

【问题讨论】:

  • @imk 很明显,OP 已经知道这一点,因为问题的重点是关于 为什么 编译器需要初始化。
  • Java 编译器根本没有进行足够深入的分析来得出结论,在使用变量myVar 之前总是将值分配给它。通常,它不会尝试关联不同条件语句中的条件。
  • 我不认为编译器知道条件不会改变。举个例子,这是在中断的 CPU 上运行的。当它返回执行此操作时,条件可能会发生变化。没关系,我没有看条件声明。 @JohnBollinger 似乎已经足够了。
  • 很感兴趣,我尝试了这个特定的场景,它在 jdk1.8.0_141 中使用 javac 编译并运行没有问题。
  • @d.j.brown 那是因为您将编译时常量true 分配给了condition。如果你用运行时值初始化它,它会失败。

标签: java variables compiler-errors variable-initialization javacompiler


【解决方案1】:

初始化要求是 Java 的正式部分,如 JLS 中所述:

对于局部变量或空白最终字段 x 的每次访问,必须在访问之前明确分配 x,否则会发生编译时错误。

(JLS 8, chapter 16; 强调原文)

JLS 继续说

分析考虑了语句的结构和 表达式;它还提供了对表达式的特殊处理 运算符!&amp;&amp;||? :,以及布尔值常量 表达式。

条件布尔运算符的特殊处理除外 &amp;&amp;||? : 以及布尔值常量表达式,值 流分析中不考虑表达式的数量

(强调)

请注意,conditionfinal 并不使其成为规范定义的“常量表达式”。规范继续给the specific rule for if statements

Vif (e) S 之后 [un] 分配,当 VS 之后 [un] 分配且 Ve 之后 [un] 分配 [e 评估为] @ 987654340@.

在您的特定代码中,然后:

int myVar;

myVar 绝对是un在这里分配的。

final boolean condition = <someCondition>;
if (condition) {
   myVar = 1;
}

myVar 是“在 S 之后赋值”,因为 if 语句的主体 S 执行无条件赋值。 myVar 在条件评估后分配,但是,无论条件评估为true 还是false。因此,myVar 在方法中此时并未明确赋值。

if (condition) {

在这一点上没有任何改变:myVar 就 JLS 规则而言仍然没有被明确分配,所以它的值不能被读取。因此编译器有义务在下一条语句中报告错误:

   System.out.println("myVar = " + myVar);
}

【讨论】:

    猜你喜欢
    • 2015-05-13
    • 2012-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-08
    • 1970-01-01
    • 2012-10-25
    • 2023-01-10
    相关资源
    最近更新 更多