Ternary和If/Else是否可以编译成相同的东西,为什么呢? [英] Do Ternary and If/Else compile to the same thing, why?
问题描述
编译器是否将简单的三元语句编译为与编译简单的if语句相同的东西?另外,为什么要设计一个编译器来以不同的方式编译它们?
Do compilers compile a simple ternary statement to the same thing that they would compile a simple if else statement? Also, why would a compiler be designed to compile them differently?
例如,会这样:
int a = 169;
int b = 420;
int c;
c = a > b ? 42:69;
编译成与此相同的东西:
compile to the same thing as this:
int a = 169;
int b = 420;
int c;
if(a>b) c = 42;
else c = 69;
这个问题不是关于哪个更好,何时使用每个问题,因此请不要在回答中包括它.
This question is not about which is better or when to use each one, so please don't include that in your answer.
推荐答案
首先,这与实现有关.只要字节码在支持Java虚拟机规范的VM上运行时,字节码满足Java语言规范,JLS便没有确切规定必须如何编译特定的代码片段或操作.只要在兼容的JVM上运行时产生相同的结果,则不同的编译器可以生成与给定示例不同的字节码.
First of all, this is implementation-dependent. The JLS does not specify exactly how a specific snippet or operation must be compiled, as long as the bytecode satistifes the Java Language Specification when run on a VM supporting the Java Virtual Machine specification. A different compiler can generate bytecode that is different from the examples given, as long as it gives the same result when run on a compliant JVM.
在Java 8的 javac
(1.8.0_65)上,条件运算符和if-else的代码不同.
On Java 8's javac
(1.8.0_65), the code is not the same for the conditional operator, and the if-else.
三元运算符控制将哪个值压入堆栈,然后无条件存储堆栈顶部的值.在这种情况下,如果 a> b
,则推送42,代码跳至 istore
,否则,推送59.然后,将最上面的任何值 istore
转换为 c
.
The ternary operator controls which value is pushed to the stack, and then the value on the top of the stack is stored unconditionally. In this case, if a>b
, 42 is pushed and code jumps to the istore
, else 59 is pushed. Then whatever value is on top is istore
d to c
.
在if-else中,条件控制实际调用哪个 istore
指令.
In the if-else, the conditional controls which istore
instruction is actually called.
但是请注意,在这两种情况下,指令都是"compare小于或等于",它会跳转到else分支(否则继续if分支).
Notice however that in both cases the instruction is "compare less than or equal" which jumps to the else branch (continuing the if branch otherwise).
下面可以看到各种编译器生成的字节码.您可以使用OpenJDK JDK中提供的 javap
工具自己获得它(示例命令行 javap -c ClassName
)
Below can be seen the bytecode generated by various compilers. You can get it yourself using the javap
tool available in an OpenJDK JDK (example command-line javap -c ClassName
)
具有三进制的javac:
javac with ternary:
public static void main(java.lang.String...);
Code:
0: sipush 169
3: istore_1
4: sipush 420
7: istore_2
8: iload_1
9: iload_2
10: if_icmple 18
13: bipush 42
15: goto 20
18: bipush 69
20: istore_3
21: return
带有if-else的javac:
javac with if-else:
public static void main(java.lang.String...);
Code:
0: sipush 169
3: istore_1
4: sipush 420
7: istore_2
8: iload_1
9: iload_2
10: if_icmple 19
13: bipush 42
15: istore_3
16: goto 22
19: bipush 69
21: istore_3
22: return
}
但是,使用 ecj
时,代码更加奇怪.三元运算符有条件地推送一个或另一个值,然后将其弹出以丢弃它(不存储):
However, with ecj
, the code is even more odd. Ternary operator conditionally pushes one or the other value, then pops it to discard it (without storing):
Code:
0: sipush 169
3: istore_1
4: sipush 420
7: istore_2
8: iload_1
9: iload_2
10: if_icmple 18
13: bipush 42
15: goto 20
18: bipush 69
20: pop
21: return
ecj
和if-else可以优化推送/存储,但是仍然包括一个奇数比较(请注意,比较没有副作用,需要保留):
ecj
with if-else somehow optimizes out the pushes/stores but still includes an oddball comparison (mind you, there are no side effects to the comparison that need to be retained):
Code:
0: sipush 169
3: istore_1
4: sipush 420
7: istore_2
8: iload_1
9: iload_2
10: if_icmple 13
13: return
当我添加一个 System.out.println(c)
来阻止这种未使用的值丢弃时,我发现这两个语句的结构与 javac
(三元进行条件推送和固定存储,而if-else进行条件存储).
When I add a System.out.println(c)
to foil this unused-value discard, I find that the structure of both statements is similar to that of javac
(ternary does conditional push and fixed store, while if-else does conditional store).
这篇关于Ternary和If/Else是否可以编译成相同的东西,为什么呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!