Java反编译器如何区分for循环和while循环?

14

考虑这两种方法:

public static void forLoop(int start, int limit) {
    for (int i = start; i < limit; i++) {

    }
}

public static void whileLoop(int start, int limit) {
    int i = start;
    while (i < limit) {
        i++;
    }
}

编译后,它们会生成字节码(这是使用javap的详细输出):

  public static void forLoop(int, int);
    descriptor: (II)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=2
         0: iload_0
         1: istore_2
         2: iload_2
         3: iload_1
         4: if_icmpge     13
         7: iinc          2, 1
        10: goto          2
        13: return
      LineNumberTable:
        line 6: 0
        line 9: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            2      11     2     i   I
            0      14     0 start   I
            0      14     1 limit   I

  public static void whileLoop(int, int);
    descriptor: (II)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=2
         0: iload_0
         1: istore_2
         2: iload_2
         3: iload_1
         4: if_icmpge     13
         7: iinc          2, 1
        10: goto          2
        13: return
      LineNumberTable:
        line 12: 0
        line 13: 2
        line 14: 7
        line 16: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0 start   I
            0      14     1 limit   I
            2      12     2     i   I

正如您所看到的,这两种方法的代码部分完全相同。然而,当我使用JD反编译此类时,它会正确地生成:

public static void forLoop(int start, int limit) {
  for (int i = start; i < limit; i++) {}
}

public static void whileLoop(int start, int limit)
{
  int i = start;
  while (i < limit) {
    i++;
  }
}

它是如何做到这一点的?这些方法的字节码完全相同!尽管每个方法的LineNumberTableLocalVariableTable属性不同,但我不愿意相信这是原因,因为这些属性不是Code属性必须包含的属性(参见Java语言规范第8版第4.7节)。

1个回答

5
行号和局部变量作用域。 for循环:
 LineNumberTable:
    line 6: 0
    line 9: 13
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        2      11     2     i   I
        0      14     0 start   I
        0      14     1 limit   I

while loop:

LineNumberTable:
        line 12: 0
        line 13: 2
        line 14: 7
        line 16: 13
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        0      14     0 start   I
        0      14     1 limit   I
        2      12     2     i   I
for循环的代码行数较少 - 这是有道理的,因为它将初始化和增量包含在一行中。

2
编译后的代码为什么需要知道局部变量的作用域? - shmosel
我的猜测是它有助于更有效地利用本地变量列表。例如,如果存储在索引2中的局部变量超出范围,编译器知道它可以重新使用索引2来存储另一个局部变量。如果不重新使用索引,则每个方法的“最大本地变量”将等同于在该方法中声明的局部变量数,而不是在该方法中某个范围内可见的最大局部变量数。 - Martin Tuskevicius
@MartinTuskevicius 这些都可以在编译时计算。 - shmosel
@MartinTuskevicius 这一切都是真的,但它描述的是编译时操作。 - user207421
@shmosel 对象文件中没有作用域信息。有调试和堆栈跟踪信息,但执行代码时不需要它们。 - user207421
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接