为什么方法1和方法2在字节码级别相同?

Jos*_*h M 21 java bytecode

我编写了这个简单的Test类来了解Java如何boolean在字节码级别评估代数:

public class Test {

    private static boolean a, b;

    public static boolean method1(){
        return !(a || b);
    }

    public static boolean method2(){
        return !a && !b;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你简化method1()使用DeMorgan的法则,你应该得到method2().在查看字节码(使用javap -c Test.class)后,它看起来像:

Compiled from "Test.java"
public class Test {
    public Test();
    Code:
            0: aload_0
    1: invokespecial #1                  // Method java/lang/Object."<init>":
            ()V
    4: return

    public static boolean method1();
    Code:
            0: getstatic     #2                  // Field a:Z
            3: ifne          16
            6: getstatic     #3                  // Field b:Z
            9: ifne          16
            12: iconst_1
    13: goto          17
            16: iconst_0
    17: ireturn

    public static boolean method2();
    Code:
            0: getstatic     #2                  // Field a:Z
            3: ifne          16
            6: getstatic     #3                  // Field b:Z
            9: ifne          16
            12: iconst_1
    13: goto          17
            16: iconst_0
    17: ireturn
}
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,为什么method1()method2()在字节码级完全一样?

Dev*_*Dev 34

您所看到的是编译器优化.当javac遇到method1()它时,它会应用优化(根据您指出的De Morgan定律,但也会使&& 比较短路),如果atrue(因此无需评估b),它可以提前分支.

  • 很好的答案,特别是早期的分支声明. (3认同)
  • 但是在`method1`中,如果`a`为真,它也不能早期分支,因为没有必要评估`b`? (3认同)

das*_*ght 18

为什么在字节码级别method1method2相同?

如果将De Morgan的转换应用于它,你可以通过指出两种方法的等价性来自己回答这个问题.

但为什么method1看起来像method2,而不是method2看起来像method1

这个假设是不正确的:它不是method1看起来像method2method2看起来像method1:相反,两个方法看起来像一些methodX,看起来像这样:

public static boolean methodX() {
    if (a) {
        return false;
    }
    return !b;
}
Run Code Online (Sandbox Code Playgroud)

由于短路,两种方法都简化为该逻辑.然后,优化器ireturn通过将gotos 插入到不同的标签来合并这两个分支.


Jon*_*nne 7

如你所说,两种方法表达相同的数学.特定编译器如何生成字节码取决于编译器作者,只要它是正确的.

编译器应用DeMorgan定律并不完全确定.在我看来,可能有更简单的优化技术可以导致相同的优化.

  • +1表示*完全没有确定编译器应用DeMorgan定律*. (2认同)

Ada*_*zyk 6

因为您的Java编译器正在优化(使用短路评估)同一字节码的两种方法:

0: getstatic     #2 // static boolean a
3: ifne          16 // if a != 0 jump to 16 (return false)
6: getstatic     #3 // static boolean b
9: ifne          16 // if b != 0 jump to 16 (return false)
12: iconst_1        // push int value 1 on the top of the stack
13: goto         17
16: iconst_0        // push int value 0 on the top of the stack
17: ireturn         // return an int from the top of the stack
Run Code Online (Sandbox Code Playgroud)