转:http://blog.csdn.net/damoyan/article/details/7384602
版权声明:本文为博主原创文章,未经博主允许不得转载。
这几天抽着一些时间,把Java的class文件结构研究了一下,再后来就想起了这个令人厌烦的问题,想从字节码指令的角度看看,java到底是怎么处理这个的
先看一段java代码
- package bishi;
- public class PlusPlusTest {
- public static void main(String[] args) {
- int i = 1;
- i = i++ + i++ + i++;
- System.out.println(i);
- int j = 1;
- j = ++j + ++j + ++j;
- System.out.println(j);
- }
- }
package bishi;
public class PlusPlusTest {
public static void main(String[] args) {
int i = 1;
i = i++ + i++ + i++;
System.out.println(i);
int j = 1;
j = ++j + ++j + ++j;
System.out.println(j);
}
}
打印的i和j分别是多少呢?
先分析i++:
- int i = 1;
- i = i++ + i++ + i++;
- System.out.println(i);
int i = 1;
i = i++ + i++ + i++;
System.out.println(i);
这三句对应的字节码为:
- 0 iconst_1 //将int类型的数字1push到栈顶
- 1 istore_1 [i] //将栈顶的1存到变量i中, 这就是int i=1;
0 iconst_1 //将int类型的数字1push到栈顶
1 istore_1 [i] //将栈顶的1存到变量i中, 这就是int i=1;
- 2 iload_1 [i] //把i的值再压栈,即栈顶存入1
- 3 iinc 1 1 [i] //把i变量中的值加1,此时i中存的是2,但是栈顶的值是1
- 6 iload_1 [i] //把i的值压栈,此时栈顶和栈顶第二个分别是2,1
- 7 iinc 1 1 [i] //把i变量中的值加1,此时i中存的是3,
- 10 iadd //把栈顶两个int类型的值相加,并把结果存入栈顶,即现在的栈,从栈顶往下依次存了3,2,1
- 11 iload_1 [i] //把i压栈,栈中自顶向下依次是3,3,2,1
- 12 iinc 1 1 [i] //把i变量中的值再加1,i中存的是4了
- 15 iadd //同10,执行完之后,栈顶为6
- 16 istore_1 [i] //将栈顶int型值存入i中,即执行完此步,i=6,到这一步就是整个 i = i++ + i++ + i++;
- 17 getstatic java.lang.System.out : java.io.PrintStream [16]
- 20 iload_1 [i] //这一步把i中的6再次push到栈顶
- 21 invokevirtual java.io.PrintStream.println(int) : void [22] //输出栈顶的6
2 iload_1 [i] //把i的值再压栈,即栈顶存入1
3 iinc 1 1 [i] //把i变量中的值加1,此时i中存的是2,但是栈顶的值是1
6 iload_1 [i] //把i的值压栈,此时栈顶和栈顶第二个分别是2,1
7 iinc 1 1 [i] //把i变量中的值加1,此时i中存的是3,
10 iadd //把栈顶两个int类型的值相加,并把结果存入栈顶,即现在的栈,从栈顶往下依次存了3,2,1
11 iload_1 [i] //把i压栈,栈中自顶向下依次是3,3,2,1
12 iinc 1 1 [i] //把i变量中的值再加1,i中存的是4了
15 iadd //同10,执行完之后,栈顶为6
16 istore_1 [i] //将栈顶int型值存入i中,即执行完此步,i=6,到这一步就是整个 i = i++ + i++ + i++;
17 getstatic java.lang.System.out : java.io.PrintStream [16]
20 iload_1 [i] //这一步把i中的6再次push到栈顶
21 invokevirtual java.io.PrintStream.println(int) : void [22] //输出栈顶的6
java虚拟机内存空间中存在一个叫java方法栈的区域,在这里为每个方法提供一个栈帧,在栈帧中存放了该方法的局部变量表,操作栈,动态链接,方法出口等信息。上面字节码中指令所指的栈应该就是这个操作栈吧(个人理解,不保证正确~)。
分析完i++,下面来看看++j的原理
- int j = 1;
- j = ++j + ++j + ++j;
- System.out.println(j);
int j = 1;
j = ++j + ++j + ++j;
System.out.println(j);
对应的字节码为:
- 24 iconst_1
- 25 istore_2 [j] //int j=1;
- 26 iinc 2 1 [j] //把j加1,j=2
- 29 iload_2 [j] //把j的值压栈,此时栈顶为2
- 30 iinc 2 1 [j] //把j加1,j=3
- 33 iload_2 [j] //把j的值压栈,栈顶往下依次为3,2
- 34 iadd //把栈顶两int类型数相加,结果压栈,栈顶往下:5,3,2
- 35 iinc 2 1 [j] //把j加1,j=4
- 38 iload_2 [j] //把j压栈,栈顶向下:4,5,3,2
- 39 iadd //把栈顶两int相加,结果压栈,栈顶往下:9,4,5,3,2
- 40 istore_2 [j] //把栈顶存入j,j=9,至此,j = ++j + ++j + ++j;执行完毕
- 41 getstatic java.lang.System.out : java.io.PrintStream [16]
- 44 iload_2 [j]
- 45 invokevirtual java.io.PrintStream.println(int) : void [22]
24 iconst_1
25 istore_2 [j] //int j=1;
26 iinc 2 1 [j] //把j加1,j=2
29 iload_2 [j] //把j的值压栈,此时栈顶为2
30 iinc 2 1 [j] //把j加1,j=3
33 iload_2 [j] //把j的值压栈,栈顶往下依次为3,2
34 iadd //把栈顶两int类型数相加,结果压栈,栈顶往下:5,3,2
35 iinc 2 1 [j] //把j加1,j=4
38 iload_2 [j] //把j压栈,栈顶向下:4,5,3,2
39 iadd //把栈顶两int相加,结果压栈,栈顶往下:9,4,5,3,2
40 istore_2 [j] //把栈顶存入j,j=9,至此,j = ++j + ++j + ++j;执行完毕
41 getstatic java.lang.System.out : java.io.PrintStream [16]
44 iload_2 [j]
45 invokevirtual java.io.PrintStream.println(int) : void [22]
总结
i++和++i的区别就是在进入操作栈和自加的顺序,呃,说完怎么跟没说一样……