先看一段代码
public class NumIncreTest {
public static void main(String[] args) {
int num = 0;
for (int i = 0; i < 50; i++) {
num = num++;
}
System.out.println(num);
}
}
输出是0
为啥是0,不是50呢?
早期我们大多是这样理解的, ++操作是滞后于赋值操作的
num = num;
num ++;
那为啥是这样的呢?
我们从字节码角度来看下
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: bipush 50
7: if_icmpge 21
10: iload_1
11: iinc 1, 1
14: istore_1
15: iinc 2, 1
18: goto 4
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return
关键看字节码 10~14行
10: iload_1
11: iinc 1, 1
14: istore_1
先把局部变量表的slot1 的变量num 加载出来,值为0,栈中的数是0
再对局部变量表的slot1 + 1,得1
再把栈中的0 store 到局部变量表的slot1 ,把1覆盖了,又成0
循环50次,还是0。。。
再来一个++i的例子
public class NumIncreTest1 {
public static void main(String[] args) {
int num = 0;
for (int i = 0; i < 50; i++) {
num = ++num;
}
System.out.println(num); // 50
}
}
这个输出是50
同样看下字节码
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: bipush 50
7: if_icmpge 21
10: iinc 1, 1
13: iload_1
14: istore_1
15: iinc 2, 1
18: goto 4
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return
可以看下区别哈~
10: iinc 1, 1
13: iload_1
14: istore_1
++i 是先在局部变量表做++操作,再load
因此++的值可以读到,生效
i++ | ++i |
10: iload_1 11: iinc 1, 1 14: istore_1 | 10: iinc 1, 1 13: iload_1 14: istore_1 |
有了前面的铺垫,我们再来看一个稍难点的
public class NumIncreTest2 {
public static void main(String[] args) {
int num = 0;
num = num++ + ++num;
System.out.println(num);
}
}
先揭晓答案 2
看下字节码
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: iinc 1, 1
6: iinc 1, 1
9: iload_1
10: iadd
11: istore_1
12: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
15: iload_1
16: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
19: return
把字节码翻译成图就是上面这个吊样子啦
如果用伪代码来理解就是
num = 0;
tmp1 = num;
num = num + 1;
num = num + 1;
tmp2 = num;
tmpSum = tmp1 + tmp2;
num = tmpSum;
转载请注明:汪明鑫的个人博客 » 从字节码角度理解 i++ 和 ++i
说点什么
您将是第一位评论人!