以下是三元运算符的有趣测试:
public int so( final int a ) {
int r = (int) System.currentTimeMillis();
r += a == 2 ? 1 : 0;
return r;
}
这是生成的字节码:
public int doIt(int);
Code:
0: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
3: l2i
4: istore_2
5: iload_2
6: iload_1
7: iconst_2
8: if_icmpne 15
11: iconst_1
12: goto 16
15: iconst_0
16: iadd
17: istore_2
18: iload_2
19: ireturn
我有点惊讶地发现它没有删除'+ 0'的'else'情况。我更期待这个:
public int doIt(int);
Code:
0: invokestatic #2; //Method java/lang/System.currentTimeMillis:()J
3: l2i
4: istore_2
5: iload_1
6: iconst_2
7: if_icmpne 13
10: iinc 2, 1
13: iload_2
14: ireturn
所以这就是我的问题:规范是否要求:
goto ...
iconst_0
序列,因为我使用了三元运算符,或者这只是一个编译器的东西?
显然这个问题不是关于写'r + = ...的相关性? 1:0'。但我很惊讶,因为在其他情况下编译器会做一些优化,而在这里它没有进行任何优化。
生成选项2的Java编译器是否仍然是一个有效的Java编译器(如果我没有搞砸我的例子,但关键是:在编写的代码中有一个不必要的0和一个不必要的goto,编译器会不会删除它仍然是一个有效的.java编译器)?
答案 0 :(得分:3)
要记住的一件事是javac
(字节码编译器的Java源代码)不是优化编译器。事实上,它在代码生成方面相对简单,只产生任何给定源代码的最直接的字节码实现。
这完全是设计上的。通过这种方式,负责所有实际优化的JVM具有可用于其决策的最大信息量。在这种特殊情况下,该信息如何使JIT编译器受益可能并不明显,但由于HotSpot优化的性质,例如,每一点信息都可以提供帮助。
例如,可能存在一些智能模式匹配,它们识别常见的代码片段并在高度优化的版本中实现它们。现在,如果javac
尝试进行一些优化,那么这些模式可能更难以检测。
答案 1 :(得分:2)
Sun的Javac本身没有做任何优化,因为它们留给了HotSpot VM。因此它产生第一个字节码。
第二个字节码列表与第一个字节码列表一样有效。所以在理论上,其他一些Java编译器可以产生这种效果。
如果没有JIT的VM(例如Android设备)需要这种优化,那么像Proguard这样的工具会对字节码级别进行优化。