考虑以下非常简单的循环,它有点间隔:
/* 01 */ System.out.println(10);
/* 02 */ for(
/* 03 */ int i = 0;
/* 04 */ i < 100;
/* 05 */ i++)
/* 06 */ System.out.println(i);
第1行并不重要。只有在循环本身之前才为Eclipse调试器创建一个起始点。
当我在调试器中运行我的代码时,我希望看到以下行的运行顺序:
1,3,4,接着是重复的6,5,4,(6,5,4,6,5,4,6,5,4 ......)系列
相反,我得到的是
1,3,4,然后是重复序列 2 ,6,5,4,( 2 ,6,5,4, 2 < / strong>,6,5,4 ......)
显然,这没什么实际意义 - 循环完全按预期运行。但是我计划为我的类创建一个新概念的演示,而这个额外的执行步骤使我提出的(有点困难)代码在调试器中更难以遵循。
我希望能够通过向他们解释正在发生的事情来抵消一些混乱。为什么第2行被重新表示为一个步骤?那一刻发生了什么?
答案 0 :(得分:4)
这是因为Java字节码具有用于比较+跳转的单个融合指令,并且一条指令是可以具有行号或可以逐步通过的最小量子。
您正在使用的Eclipse ECJ似乎强调跳转,并将compare + jump作为for
循环本身的一部分进行注释。这导致在每次比较/跳跃期间02
停止。
OpenJDK似乎强调“比较”方面,并将其注释为for循环条件的一部分。这会给出您期望的结果,而不会停留在02
。
两者都没有直接错,但我也倾向于赞成你的解释。也许你可以说服Eclipse使用OpenJDK进行这个特定的演示,或者使用不同的Java调试器?
下面是反汇编的字节码+调试信息。欧洲法院将条件放在最底层:
public static void main(java.lang.String[]);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
8: iconst_0
9: istore_1
10: goto 23
13: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
16: iload_1
17: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
20: iinc 1, 1
23: iload_1
24: bipush 100
26: if_icmplt 13 // HERE
29: return
LineNumberTable:
line 3: 0
line 5: 8
line 6: 10
line 8: 13
line 7: 20
line 6: 23
line 4: 26 /* 02 */ in your code
line 9: 29
OpenJDK提供更直接的翻译,需要一个倒置条件,其中没有使用for(
行注释指令:
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
8: iconst_0
9: istore_1
10: iload_1
11: bipush 100
13: if_icmpge 29
16: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
19: iload_1
20: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
23: iinc 1, 1
26: goto 10
29: return
LineNumberTable:
line 3: 0
line 5: 8
line 6: 10
line 8: 16
line 7: 23
line 9: 29