i++
在初次学习i++
和++i
时我们就一直牢记着:i++
是先使用后加1,++i
是先加1再使用,长时间都一直这样搬着砖(这结论当然是没毛病的),我也是。直到我看见了下面的题目。
public static void func(){
int i=0;
for(int j=0;j < 100;j++){
i = i++;
}
Stystem.out.println(i);//打印什么???
}
我是觉得打印100的,毫无疑问,我错了。
看来我还是太菜了,看看字节码吧!
0 iconst_0
1 istore_0
2 iconst_0
3 istore_1
4 iload_1
5 bipush 100
7 if_icmpge 21 (+14)
10 iload_0
11 iinc 0,1
14 istore_0
15 iinc 1,1
18 goto 4 (-14)
21 getstatic #2 <java/lang/System.out>
24 iload_0
25 invokevirtual #3 <java/io/PrintStream.println>
28 return
其中10~14对应的就是i=i++
的字节码。强烈建议给IDEA安装上Jclasslib插件,这样能更方便的指定助记符的含义。
- iload_0: 将当前栈帧的局部变量数组的索引为0的局部变量的值推送到操作数堆栈上。
- iinc 0,1: 将索引为0的局部变量按1递增。
- istore_0: 将值从操作数堆栈中弹出(记为val),并且将索引为0的局部变量值设置为val。
看完这三个助记符我们就会发现iinc
虽然讲值递增了,但是没有设置给i,所以i的值一直没有变,i++
完全没有任何作用。动图如下:
嗯,就这样,i被改变后又被栈上的值给覆盖了~_~
++i
现在我们换一下题,换成++i
。
public static void func(){
int i=0;
for(int j=0;j < 100;j++){
i = ++i;
}
Stystem.out.println(i);//打印什么???
}
对应字节码如下。
0 iconst_0
1 istore_0
2 iconst_0
3 istore_1
4 iload_1
5 bipush 100
7 if_icmpge 21 (+14)
10 iinc 0,1
13 iload_0
14 istore_0
15 iinc 1,1
18 goto 4 (-14)
21 getstatic #2 <java/lang/System.out>
24 iload_0
25 invokevirtual #3 <java/io/PrintStream.println>
依旧是不变的10~14行,
如此i就可以被改变了,打印100。
混合操作
在i++
和++i
的笔试题中经常混合使用,一堆+号头疼。如:i= (i++)+(i++)+(++i)+(++i);
。咱先来个简单的(如i = i++ + ++i;
),否则字节码都迷糊了。其实这个的答案很简单,只是我们需要通过它的字节码更理解而已。字节码如下。
0 iconst_0
1 istore_0
2 iload_0
3 iinc 0,1
6 iinc 0,1
9 iload_0
10 iadd
11 istore_0
12 getstatic #2 <java/lang/System.out>
15 iload_0
16 invokevirtual #3 <java/io/PrintStream.println>
19 return
我们只需要关注2~11行,这几步对应的值和栈如下图所示。画图这也是本文的目的所在。
困难模式
来,画它i= (i++)+(i++)+(++i)+(++i);
,看看看官能否画出过程图呢^_^。字节码如下。
0 iconst_0
1 istore_0
2 iload_0
3 iinc 0,1
6 iload_0
7 iinc 0,1
10 iadd
11 iinc 0,1
14 iload_0
15 iadd
16 iinc 0,1
19 iload_0
20 iadd
21 istore_0
22 getstatic #2 <java/lang/System.out>
25 iload_0
26 invokevirtual #3 <java/io/PrintStream.println>
29 return
我们只需要关注2~21行。
版权属于:带翅膀的猫
本文链接:https://www.chengpengper.cn/archives/75/
转载时须注明出处及本声明