我编写了这个简单的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定律,但也会使&& 比较短路),如果a是true(因此无需评估b),它可以提前分支.
das*_*ght 18
为什么在字节码级别
method1和method2相同?
如果将De Morgan的转换应用于它,你可以通过指出两种方法的等价性来自己回答这个问题.
但为什么
method1看起来像method2,而不是method2看起来像method1?
这个假设是不正确的:它不是method1看起来像method2或method2看起来像method1:相反,两个方法看起来像一些methodX,看起来像这样:
public static boolean methodX() {
if (a) {
return false;
}
return !b;
}
Run Code Online (Sandbox Code Playgroud)
由于短路,两种方法都简化为该逻辑.然后,优化器ireturn通过将gotos 插入到不同的标签来合并这两个分支.
如你所说,两种方法表达相同的数学.特定编译器如何生成字节码取决于编译器作者,只要它是正确的.
编译器应用DeMorgan定律并不完全确定.在我看来,可能有更简单的优化技术可以导致相同的优化.
因为您的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)
| 归档时间: |
|
| 查看次数: |
987 次 |
| 最近记录: |