Java字节码初学者问题:" istore"变量使用,"字节使用"等

时间:2016-01-01 19:00:23

标签: java bytecode

我有以下Java代码:

public static void fun(int[] a) {

    int min;

    for(int j=0;j<a.length-1;j++) {
        min=j;

        for(int i=j+1;i<a.length;i++) 
            if(a[i]<a[min]) min=i;

        if(min!=j) {
            int temp = a[j];
            a[j] = a[min];
            a[min]=temp;
        }
    }
}

我在上面代码生成的类文件中使用javap -c来打印上述程序的Java字节码,我得到以下输出:

0:iconst_0
1:istore_2
2:iload_2
3:aload_0
4:arraylength
5:iconst_1
6:isub
7:if_icmpge 64
10:iload_2
11:istore_1
12:iload_2
13:iconst_1
14:iadd
15:istore_3
16:iload_3
17:aload_0
18:arraylength
19:if_icmpge 39
22:aload_0
23:iload_3
24:iaload
25:aload_0
26:iload_1
27:iaload
28:if_icmpge 33
31:iload_3
32:istore_1
33:iinc 3,1 36:转到16
39:iload_1
40:iload_2
41:if_icmpeq 58
44:aload_0
45:iload_2
46:iaload
47:istore_3
48:aload_0
49:iload_2
50:aload_0
51:iload_1
52:iaload
53:iastore
54:aload_0
55:iload_1
56:iload_3
57:iastore
58:iinc 2,1,1 61:转到2
64:回归

我的问题主要涉及istore命令。如您所见,在&#34; 1:&#34;,生成的字节码为istore_2。在这种情况下,为什么使用了istore_2,而不是istore_0istore_1?我们可以看到,稍后在&#34; 11:&#34;,istore_1被使用,但istore_0不是。这有什么原因,为什么变量2在开始时使用,变量1在以后使用?

如果上述措辞严重,我很抱歉,我现在才开始在大学里学习Java字节码。

此外,我试图找出哪些命令使用了我们必须学习使用的列表中的多个字节。这是列表,有人可以验证&#34;字节的使用情况&#34; (我不确定正确的术语)在下面的命令中是否正确(我们必须在考试中手动转换,使用下面给出的命令列表,我需要了解每个命令使用的字节数 - 它是在我们的讲座中解释得非常糟糕和迅速,讲师没有在线笔记。)

&#34; aload_n&#34; - 1个字节
&#34; iconst_n&#34; - 1个字节
&#34; iaload&#34; - 1字节
&#34; istore_n&#34; - 1个字节
&#34; arraylength&#34; - 1字节
&#34; if_icmpge&#34; - 3个字节
&#34; if_icmple&#34; - 3个字节
&#34; iinc i c&#34; - 不确定? 3个字节?
&#34;转到n&#34; - 3个字节?
&#34; ireturn&#34; - 1个字节

最后,我相信goto n使用3个字节(如上所述),但是,有人可以解释为什么会这样吗?

非常感谢你的帮助,我意识到这是一个很长的问题! 劳伦

1 个答案:

答案 0 :(得分:1)

关于字节用法,您可以参考specification。引用开头的注释:“指令格式图中的每个单元代表一个8位字节”,因此应该很容易获得每条指令的大小。

  

如您所见,在“1:”处,生成的字节码为“istore_2”。在这种情况下,为什么使用“istore_2”而不是“istore_0”或“istore_1”?

仅仅因为在第1行,字节码将零值存储到恰好位于索引2的局部变量j。类似地,istore_1将操作数堆栈上的值存储到本地索引为1的变量(在本例中为min)。

这很有效,因为长话短说,每个方法都分配了一个堆栈框架,其中包含local variables,可以通过在编译时分配的索引访问。

对于goto指令,这也在specification

  

转到

     

branchbyte1

     

branchbyte2

     

无符号字节 branchbyte1 branchbyte2 用于构造带符号的16位分支偏移,其中 branchoffset 是( branchbyte1 &lt;&lt; 8)| branchbyte2 。执行从该 goto 指令的操作码的地址开始。目标地址必须是包含此 goto 指令的方法中指令的操作码的地址。

操作码后面有两个字节,它组成16位偏移量。生成的目标地址计算如下:

  

target_address = address_of_current_goto + 16_bit_offset