public class Test1 {
static final int i;
static{
if(3<2){
i = 0;
}
}
}
public class Test2 {
static final int i;
static{
if(3>2){
i = 0;
}
}
}
类Test1
无法编译,
类Test2
已成功编译。
任何正文都可以告诉我编译器如何在if条件下评估表达式吗?
答案 0 :(得分:5)
static final int i;
需要在静态初始化程序中初始化,因为它是最终的。
static{
if(3<2){
i = 0;
}
}
因为3&lt; 2字面或常量,编译器能够检测到你死的部分代码并且不初始化i。
添加else
个案并在那里进行一些i
初始化。
答案 1 :(得分:2)
它与编译器如何确定是否将执行语句有关。它在JLS #16:
中定义当对其值进行任何访问时,每个局部变量和每个空白最终字段必须具有明确赋值。
在您的示例中,编译器可以确定i
在编译时是否(或不是)明确赋值,因为if
中的表达式是常量表达式。
JLS #15.28定义常量表达式:
编译时常量表达式是表示基本类型值的表达式或不突然完成的字符串,仅使用以下内容组成:
- 原始类型的文字[...]
- 关系运算符&lt;,&lt; =,&gt;和&gt; = [...]
有趣的是,尽管Test2编译了,但是这个修改版的Test2不能编译:
static class Test3 {
static final int i;
static {
int j = 3;
if (j > 2) {
i = 0;
}
}
}
原因是j > 2
不再是常量表达式。使j final
会使类再次编译。
答案 2 :(得分:2)
根据Java Language Specification,if语句的条件部分中的表达式是编译时表达式。在Test1编译器知道我将永远不会被初始化,这就是它抱怨的原因。在第二种情况下,编译器知道我将被初始化。如果用更动态的东西替换编译时表达式,则两个类都将无法编译,因为编译器将无法保证i被初始化。
答案 3 :(得分:0)
if (3<2)
可以优化为if (false)
,因此Java编译会检测到无法访问的语句(错误)。
if (3>2)
可以优化为if (true)
,然后始终执行随附的语句。没问题。
编译器可以轻松检测到这些是常量标量,因此可以在编译时评估(即优化)表达式。我们期望从一个体面的编译器中获得更少的东西。