【问题标题】:Java conditionals in class-file (on bytecode level)类文件中的 Java 条件(字节码级别)
【发布时间】:2026-01-12 22:55:01
【问题描述】:

我正在使用 Java 类文件和字节码。但我坚持类文件中的条件。 理论上,我理解这个概念,但我不明白类文件中的分支是如何完成的。这是一个小例子:

public static void main(String[] args) {
  int a = 78;
  int b = 52;
  boolean c;

  if(a==b){
    c = true;
  } else {
    c = false;
  }
}

使用 javap -c -verbose Equal.class 会出现以下清单:

flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        78
         2: istore_1      
         3: bipush        52
         5: istore_2      
         6: iload_1       
         7: iload_2       
         8: if_icmpne     16
        11: iconst_1      
        12: istore_3      
        13: goto          18
        16: iconst_0      
        17: istore_3      
        18: return        
      LineNumberTable:
        line 4: 0
        line 5: 3
        line 7: 6
        line 8: 11
        line 10: 16
        line 11: 18
      StackMapTable: number_of_entries = 2
           frame_type = 253 /* append */
             offset_delta = 16
        locals = [ int, int ]
           frame_type = 252 /* append */
             offset_delta = 1
        locals = [ int ]

现在我正在查看类文件,以找到分支。操作码 if_icmpne 的十六进制表示是 0xA0。我假设分支标记将跟随 0xA0。就我而言,有 2 个字节:0x0008。 我的问题:这两个字节(0x0008)代表什么? 我尝试了很多。例如,我沿着 LineNumberTable 和常量池的路径,但找不到任何有意义的东西。

(当然 goto 也一样)

此外,这里是上面 postet 列表的完整序列:

10 4E  // bipush 78
3C     // istore_1
10 34  // bipush 52
3D     // istore_2
1B     // iload_1
1C     // iload_2
A0     // if_icmpne
00 08  // ???
04     // iconst_1
3E     // istore_3
A7     // goto
00 05  // ???
03     // iconst_0
3E     // istore_3
B1     // return

提前谢谢你!

【问题讨论】:

    标签: java branch bytecode .class-file conditional


    【解决方案1】:

    0x0008 是分支偏移量 - 即从当前指令向前跳转以查找下一条指令的字节数。所以从if_icmpne跳转8个字节(->00->08->04->3E->A7->00->05->03)到iconst_0goto也是一样:从goto跳转5个字节(->00->05->03->3E->B1)到return

    【讨论】:

    • 天哪,这真的很简单 xD 非常感谢你让我大开眼界!
    • 这个问题的另一个问题。您可能知道如何生成那些“跳转”字节吗?因为在生成第一个 if_icmpne 时需要知道跳转到哪里。
    • @ksascha 你基本上必须在两次传球中完成,至少对于向前跳跃。
    • 那么,我必须计算 if_icmpne 之后的字节数,并在 if_icmpne 之后的第二步中写入这些字节数?跨度>
    • 是的,在第一遍中,您只需保留 2 个字节,继续生成代码,然后计算从跳转位置到跳转目标的字节并将它们放入这两个字节中。