Pra*_*anD 54 java conditional final initialization
class Foo{
public static void main(String args[]){
final int x=101;
int y;
if(x>100){
y=-1;
}
System.out.println(y);
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我将x的声明和初始化分成两行时,编译器似乎并不认为条件总是为真,并且y将始终被初始化.
final int x;
x=101;
byte b;
b=x;
System.out.println(b);
Run Code Online (Sandbox Code Playgroud)
这里发生了同样的事情,编译器会丢失精度错误.
final int x=101;
byte b;
b=x;
System.out.println(b);
Run Code Online (Sandbox Code Playgroud)
同样,编译器可以理解x在b的范围内.
Pat*_*han 46
作为针对可移植性的一部分,有一组非常具体的规则,用于编译器应该接受什么以及它应该拒绝什么.这些规则在确定变量是否在其使用时明确赋值时,允许并且仅需要有限形式的流分析.
请参阅Java语言规范第16章.定义分配
关键规则是16.2.7中的规则.如果声明,"如果(e)S"的情况.明确分配的规则扩展为:
V被分配之后,如果(E)s 如果且仅当,V之后分配小号和V之后分配ë当假.
y是相关的V.它在if语句之前未分配.确实在S之后分配,y = {y = -1;}但是当x> 100为假时没有任何分配.
因此,在if语句之后,y并未明确赋值.
更完整的流分析将确定条件x> 100始终为真,但JLS要求编译器根据这些特定规则拒绝程序.
最后的变量很好.规则实际上是: -
"如果分配了最终变量,那么这是一个编译时错误,除非在分配之前它是明确未分配的(第16段)."
声明使它绝对未分配,甚至有限的流分析也可以确定x在赋值时仍然是明确未分配的.
ass*_*ias 26
它与编译器如何确定是否将执行语句有关.它在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;不是.