如果 java 字节码中的条件反转

Reversed if condition in java bytecode

考虑简单的例子

private static String isPositive(int val) {
    if (val > 0) {
        return "yes";
    } else {
        return "no";
    }
}

这里很简单:if val > 0 return yes else return no。 但是在编译之后,在字节码中,这个 if 条件被颠倒了:

  private static isPositive(I)Ljava/lang/String;
   L0
    LINENUMBER 12 L0
    ILOAD 0
    IFLE L1
   L2
    LINENUMBER 13 L2
    LDC "yes"
    ARETURN
   L1
    LINENUMBER 15 L1
   FRAME SAME
    LDC "no"
    ARETURN

它检查:if val <= 0 then return no, else return yes.

首先,我认为 <= 检查更便宜,而且是某种优化。但是,如果我将初始代码更改为

if (val <= 0) {
    return "no";
} else {
    return "yes";
}

它仍然会在字节码中反转:

   L0
    LINENUMBER 12 L0
    ILOAD 0
    IFGT L1
   L2
    LINENUMBER 13 L2
    LDC "no"
    ARETURN
   L1
    LINENUMBER 15 L1
   FRAME SAME
    LDC "yes"
    ARETURN

那么,这种行为有原因吗?可以改成直截了当吗?

可能是这样做的,以便 if 中的两个代码块在翻译后的字节码中以相同的顺序显示。

例如,这个Java代码:

if (val > 0) {
    return "yes";
} else {
    return "no";
}

翻译成这样(伪代码):

If val <= 0, then branch to L1
return "yes"
L1:
return "no"  

请注意,在原始 Java 代码中,会检查 if 条件以查看第一个代码块是否应该 运行,而在翻译后的字节码中会完成检查查看是否应该采用该分支(跳过第一段代码)。所以它需要检查一个互补条件。

Can it be changed to straightforward?

当然也可以保留条件,但是你需要将两个代码块的顺序颠倒:

If val > 0, then branch to L1
return "no"
L1:
return "yes"  

虽然我不会说这个版本比上一个版本"more straighforward"。

不管怎样,你为什么要改变它?两个版本应该都可以。

原因可能是字节码用来执行其语句的操作数堆栈

First the comparison is performed and 1, 0 or -1 is pushed onto the operand stack. Next a branch is performed based on whether the value on the operand stack is greater, less-than or equal to zero.

JavaCodeToByteCode#conditionals 中给出了很好的图形细节 还有详细的Instruction For Branching

实际上,反转条件是最直接的编译策略。您编写 Java 匹配模式

的代码
if(condition_fullfilled) {
    somecode
}

这将被编译为与模式匹配的字节码

  goto_if_condition_not_fullfilled A_LABEL
  compiled_somecode
A_LABEL:

因为条件分支说什么时候跳过条件代码,它的条件必须与你的源代码说什么时候执行 条件代码。

上面的示例没有 else 部分,说明了为什么没有简单的方法可以使用与源代码具有相同条件的条件分支指令来编译 if。可以,但需要不止一条分支指令。

没有 elseif 语句的这种直接编译策略也可以轻松扩展以处理 else。没有理由改变策略,例如当存在 else 子句时,切换语句的顺序。

请注意,在您的情况下,两个分支都以 return 语句结尾,

之间没有区别
if (val > 0) {
    return "yes";
} else {
    return "no";
}

if (val > 0) {
    return "yes";
}
return "no";

无论如何。