为什么Java编译器不理解这个变量总是被初始化?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (12)
class Foo{
    public static void main(String args[]){
        final int x=101;

        int y;
        if(x>100){
            y=-1;
        }
        System.out.println(y);
    }
}

Java编译器理解if语句的条件始终为true,因此y将始终被初始化。没有预期的编译错误。

class Bar{
    public static void main(String args[]){
        final int x;
        x=101;

        int y;      
        if(x>100){
            y=-1;
        }
        System.out.println(y);
    }
}

但是,当我将x的声明和初始化分解为两行时,编译器似乎没有得到条件总是真的,并且y总是被初始化的。

final int x;
x=101;
byte b;
b=x;
System.out.println(b);

这里也发生了同样的事情,编译器造成了精度错误的损失。

final int x=101;
byte b;
b=x;
System.out.println(b);

同样,编译器可以理解x在b的范围内。

提问于
用户回答回答于

它与编译器如何确定语句是否被执行有关。它在JLS#16中定义:

任何访问其值时,每个局部变量和每个空白最终字段都必须具有明确分配的值。

在你的情况下,编译器不能确定它y已被明确赋值并给你一个错误。这是因为它需要确定条件始终为真,并且只有当条件if常量表达式时才有可能。

JLS#15.28定义了常量表达式

编译时常量表达式是一个表达式,用于表示基本类型的值或不会突然完成的字符串,并且仅由以下内容组成:

  • [...]
  • 简称(§6.5.6.1)涉及常量变量(§4.12.4)。

JLS#4.12.4定义常量变量为:

原始类型或类型为String的变量(最终并使用编译时常量表达式进行初始化)称为常量变量。

在你的情况下,final int x = 101;是一个常量变量,但final int x; x = 101;不是。

用户回答回答于

请参阅Java语言规范第16章定义分配

因此,在if语句之后y并不是明确赋值的。

更完整的流程分析将确定条件x> 100始终为真,但JLS要求编译器根据这些特定规则拒绝程序。

最后的变量很好。规则实际上是: -

“如果最后一个变量被赋值,除非它在赋值之前立即被赋值(§16),否则这是一个编译时错误。”

该声明完全没有指定,甚至有限的流程分析也可以确定x仍然在作业中完全未分配。

扫码关注云+社区