public class Demo02 {
public static void main(String[] args) {
test();
}
public static void test() {
int a = 3;
if (true) {
return;
}
//else return;
System.out.println(1);
}
}
如上代码,if的条件是true,这就代表这调用test方法时,return一定会执行,后面的打印语句看起来是无法执行到的,按照平常来讲,这种代码直接就会编译报错,但是实际上是没有报错,除非加上else return;才会出现报错,请问这是为什么呢?JVM在进行编译的时候是怎么编译这段代码的呢?java在编译if else的时候会检查if()中的条件么?
感谢三位大佬,从流程控制和底层帮我解释了该问题,虽然有些可能因为自己水平不够看的不清楚,但是在三位的解答中,我明白了死代码和不可达代码是不一样的,再次感谢。
为啥有死代码也没报错
编译时报错的原因一般是语法错误(比如少括号,拼错关键字),语义错误(比如在循环外使用break,把double赋值给int强制cast除外,应为这样会对操作对象重新解释,最后还是能生成底层语言),你这里有了dead code也不报错的原因是本质上他没有语法错误,也没有语义错误,也就是他们的确能够成功的转换为更底层的语言,你写的test方法,他的更底层伪类汇编代码可能会是这样的
是怎么编译这段代码的呢
编译器明显知道有死代码所以产生的底层语言可能是这样的
java在编译if else的时候会检查if()中的条件么
当然会,编译器作为计算机领域迭代了快一个世纪软件,检查常量表达是只是他其中做的一个优化而已,现在的编译器,会在常量折叠,公共表达式提取,方法内联,强度削减,优化寄存器分配(减少寄存器溢出的数量),代码局部性(减少缓存MISS的概率),指令集并行性(重排指令顺序减少指令之间的数据依赖),数据并行性(SIMD)都下足功夫
编译器是如何检测出死代码的
控制流分析:编译器会根据一个程序所有可能的跳转逻辑构建出一张控制流图,有了图之后就可以根据一些常量表达式提前将一些不可能达到的分支删除,比如test方法优化前的控制流图是这样的
由于我们可以知道程序总是会走
true
分支所以完全可以把!true
则条分支上的所有节点删除而不会影响程序的正确性,删除后的控制流图是这样的