编译器如何处理选择语句变体

时间:2014-08-05 19:16:45

标签: java compiler-construction jvm javac bytecode

以下所有三种方法在功能上都相同 - 但是它们都具有我认为的风格差异。编译它们时,编译器是否会对它们进行不同的处理? (我缺乏检查和理解反编译字节码的技术诀窍)

// Method 1
private boolean isAcceptableRange(final int a, final int b) {       
    if ((Math.abs(a - b)) <= range) {
        return true;
    } else {
        return false;
    }
}

// Method 2
private boolean isAcceptableRange(final int a, final int b) {       
    if ((Math.abs(a - b)) <= range) {
        return true;
    }
    return false;
}

// Method 3
private boolean isAcceptableRange(final int a, final int b) {
    if ((Math.abs(a - b)) <= range)
        return true;
    return false;
}

我最初的想法是#1将是唯一的,因为额外的else条款,其中#2和#3将最终相同。这意味着在优化磁盘/ ROM空间效率和可能的指令效率(思考嵌入式)时,请选择#2或#3选项。

或者编译器是否知道最终结果并“优化”它?

2 个答案:

答案 0 :(得分:4)

  

或者编译器是否知道最终结果并且&#34;优化&#34;它走了?

是的,确实如此。让我们看看生成的字节码:

javap -c -private MyClass.class
  • javap:是一个工具(除其他外)让你看到java类的字节码,它随JDK一起提供。
  • -c:将代码反汇编为字节码
  • -private:显示班级中的私人成员和方法。
  • MyClass.class:已编译的课程

private boolean isAcceptableRange1(int, int);
    Code:
       0: iload_1       
       1: iload_2       
       2: isub          
       3: invokestatic  #1                  // Method java/lang/Math.abs:(I)I
       6: aload_0       
       7: getfield      #2                  // Field range:I
      10: if_icmpgt     15
      13: iconst_1      
      14: ireturn       
      15: iconst_0      
      16: ireturn       

  private boolean isAcceptableRange2(int, int);
    Code:
       0: iload_1       
       1: iload_2       
       2: isub          
       3: invokestatic  #1                  // Method java/lang/Math.abs:(I)I
       6: aload_0       
       7: getfield      #2                  // Field range:I
      10: if_icmpgt     15
      13: iconst_1      
      14: ireturn       
      15: iconst_0      
      16: ireturn       

  private boolean isAcceptableRange3(int, int);
    Code:
       0: iload_1       
       1: iload_2       
       2: isub          
       3: invokestatic  #1                  // Method java/lang/Math.abs:(I)I
       6: aload_0       
       7: getfield      #2                  // Field range:I
      10: if_icmpgt     15
      13: iconst_1      
      14: ireturn       
      15: iconst_0      
      16: ireturn  

我调用了方法isAcceptableRange1isAcceptableRange2isAcceptableRange3。如您所见,所有方法都具有完全相同的字节码。

答案 1 :(得分:2)

我还没看过字节码。但基于我对编译器技术的一般了解:if (condition) {then-part} else {else-part}会产生看起来基本类似的代码:

if (!condition) branch to Label_1;
perform then-part;
branch to Label_2;
Label_1:
perform else-part;
Label_2:

在您的示例#1中,&#34; then-part&#34;是一个return语句。并且return语句的代码可以是return指令,也可以是子例程代码末尾某点的branch(包括任何finally那个有效)然后返回。一个体面的编译器不会在另一个无条件分支或return指令之后生成一个分支(或任何其他代码),因为该代码永远不会被执行。所以示例#1最终看起来像

if (!condition) branch to Label_1;
set return value to "true";
return or branch to cleanup code;
Label_1:
set return value to "false";
return or branch to cleanup code;

这将是示例#2或#3生成的完全相同的代码。

所以你的问题的答案是:不,编译器不会以不同的方式处理你的任何例子,除非它是一个非常糟糕的编译器。