Java字节码iconst_0 iadd序列

标签 java bytecode ternary-operator

这是一个使用三元运算符的有趣测试:

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 编译器)?

最佳答案

需要记住的一件事是,javac(Java 源代码到字节码编译器)不是优化编译器。事实上,它的代码生成相对简单,并且只生成任何给定源代码的最直接的字节码实现。

这完全是设计使然。这样,负责所有实际优化的 JVM 就拥有最大量的可用信息来做出决策。在这种特殊情况下,这些信息如何使 JIT 编译器受益可能并不明显,但由于 HotSpot 所做的优化的性质,每一个信息都可以提供帮助。

例如,可能有一些智能模式匹配可以识别常见的代码片段并在高度优化的版本中实现它们。现在,如果 javac 也尝试进行一些优化,那么这些模式可能更难检测。

关于Java字节码iconst_0 iadd序列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2317614/

相关文章:

java - 蒙戈数据库 : Pull out subdocument from a document

java - 编译器优化 : Java bytecode

java - JVM 的 LookupSwitch 和 TableSwitch 的区别?

javascript - 仅从字符串中提取数字的函数

java 三元运算符内部 + intellij 评估表达式

Java:renameTo() 函数失败

java - BouncyCaSTLe安装问题

c++ - 为什么我不能在 C++ 的三元条件语句中使用 "break"语句?

java - @PrimaryKeyJoinColumn 未选择共享 key

关于使用 Java 14 生成的 .class 的 Java 问题