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语句的条件始终为真,因此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的范围内。
发布于 2012-11-05 23:57:53
它与编译器如何确定语句是否将被执行有关。它是在JLS #16中定义的
每个局部变量和每个空的最终字段在其值发生任何访问时都必须有一个明确分配的值。
在您的例子中,编译器不能确定y
已被明确赋值,并给出一个错误。这是因为它需要确定条件始终为真,而这只有在if
中的条件是常量表达式时才有可能。
JLS #15.28定义常量表达式
编译时常量表达式是表示基元类型的值或字符串的表达式,该表达式不会突然完成,并且仅使用以下内容组成:
JLS #4.12.4将常量变量定义为:
基本类型或字符串类型的变量称为常量变量,它是最终类型,并使用编译时常量表达式进行初始化。
在您的例子中,final int x = 101;
是一个常量变量,而final int x; x = 101;
不是。
发布于 2012-11-05 23:56:18
作为可移植性目标的一部分,对于编译器应该接受什么和应该拒绝什么,有一组非常具体的规则。当确定变量在使用时是否被明确赋值时,这些规则既允许也只需要有限形式的流分析。
请参阅Java Language Specification Chapter 16. Definite Assignment
关键规则是16.2.7. if Statements中的规则,"if (e) S“。明确分配的规则扩展为:
V在if (e) S之后赋值当且仅当,V在S之后赋值,当为false时V在e之后赋值。
Y是相关的V。它在if语句之前未赋值。它确实是在S,y= {y=-1;}之后赋值的,但是当x>100为false时,没有任何东西使它赋值。
因此,在if语句之后没有明确地指定y。
更完整的流分析将确定条件x>100始终为真,但是编译器需要基于这些特定规则拒绝程序。
最后一个变量没有问题。规则实际上是:-
“如果最后一个变量被赋值,则它是编译时错误,除非它在赋值之前被明确取消赋值(§16)。”
声明肯定是未赋值的,即使是有限流分析也可以确定x在赋值时仍然是绝对未赋值的。
发布于 2012-11-06 00:13:25
您对第二段代码中的变量x
做了什么,称为空白最终变量。如果一个最终变量在声明时没有初始化,那么它就是一个空白的最终变量。
许多Java开发人员认为final变量的值在编译时是已知的。这并非总是正确的。据说空白最终变量的值在编译时是未知的。因此,您的第二个代码将给您一个编译错误。编译器可以看到您已经初始化了最后一个变量x
,但是compile不知道它的值。所以编译器不能解析if语句。因此,它认为变量y
没有初始化。
您可以阅读更多关于Java final variables here的内容。
https://stackoverflow.com/questions/13235559
复制相似问题