与Pavel Horal的回答相反,
Codo 和 yuvgin 我认为编译器不会优化(或忽略)三元运算符。 (澄清:我指的是 Java to Bytecode 编译器,而不是 JIT)
查看测试用例。
类 1:计算布尔表达式,将其存储在变量中,然后返回该变量。
public static boolean testCompiler(final int a, final int b)
{
final boolean c = ...;
return c;
}
因此,对于不同的布尔表达式,我们检查字节码:
1. 表达方式:a == b
字节码
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: istore_2
11: iload_2
12: ireturn
- 表达式:
a == b ? true : false
字节码
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: istore_2
11: iload_2
12: ireturn
- 表达式:
a == b ? false : true
字节码
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_0
6: goto 10
9: iconst_1
10: istore_2
11: iload_2
12: ireturn
情况(1)和(2)编译成完全相同的字节码,不是因为编译器优化掉了三元运算符,而是因为它本质上每次都需要执行那个微不足道的三元运算符。它需要在字节码级别指定是返回真还是假。要验证这一点,请查看案例 (3)。除了交换了第 5 行和第 9 行之外,它是完全相同的字节码。
然后a == b ? true : false 反编译产生a == b 时会发生什么?选择最简单的路径是反编译器的选择。
此外,基于“1 类”实验,可以合理地假设a == b ? true : false 与a == b 完全相同,在它被转换为字节码的方式上。然而,这不是真的。为了测试我们检查以下“类 2”,与“类 1”的唯一区别是它不会将布尔结果存储在变量中,而是立即返回它。
类 2:计算布尔表达式并返回结果(不将其存储在变量中)
public static boolean testCompiler(final int a, final int b)
{
return ...;
}
字节码:
0: iload_0
1: iload_1
2: if_icmpne 7
5: iconst_1
6: ireturn
7: iconst_0
8: ireturn
字节码
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: ireturn
字节码
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_0
6: goto 10
9: iconst_1
10: ireturn
这里很明显a == b 和 a == b ? true : false 表达式的编译方式不同,因为情况(1)和(2)产生不同的字节码(情况(正如预期的那样,2) 和 (3) 只交换了它们的第 5,9 行。
起初我发现这令人惊讶,因为我期望所有 3 个案例都是相同的(不包括案例 (3) 的交换行 5,9)。当编译器遇到a == b 时,它计算表达式并在遇到a == b ? true : false 后立即返回,它使用goto 转到行ireturn。我知道这样做是为了在三元运算符的“真实”情况下为潜在的语句留出空间:在if_icmpne 检查和goto 行之间。即使在这种情况下它只是一个布尔值 true,编译器也会像在存在更复杂块的一般情况下一样处理它。
另一方面,“1 类”实验掩盖了这一事实,因为在 true 分支中也有 istore、iload 而不仅仅是 ireturn 强制使用 goto 命令并导致完全相同情况(1)和(2)中的字节码。
作为关于测试环境的说明,这些字节码是使用最新的 Eclipse (4.10) 生成的,它使用各自的 ECJ 编译器,与 IntelliJ IDEA 使用的 javac 不同。
但是,在其他答案(使用 IntelliJ)中读取 javac 生成的字节码,我相信同样的逻辑也适用于那里,至少对于存储值且不立即返回的“类 1”实验。
最后,正如在其他答案(例如supercat 和jcsahnwaldt)中已经指出的那样,无论是在这个线程中还是在 SO 的其他问题中,重度优化都是由 JIT 编译器完成的,而不是来自java-->java-bytecode 编译器,因此这些检查虽然对字节码翻译提供了信息,但并不能很好地衡量最终优化代码将如何执行。
补充:jcsahnwaldt 的回答比较了 javac 和 ECJ 为类似情况生成的字节码
(作为免责声明,我没有对 Java 编译或反汇编进行过多研究,无法真正了解它的底层功能;我的结论主要基于上述实验的结果。)