详讲 i = i ++和 i=++ i 的区别(从字节码的角度解析)
Java 自增运算符 字节码 局部变量表 操作数栈
java代码如下
public class test {
public static void main(String[] args) {
int i=1;
i=i++;
System.out.println(i);
int j=1;
j=++j;
System.out.println(j);
}
}
先提出问题,此时读者认为最后输出的值是什么呢?
我们先不进行解答,先展示一下class反编译之后的文件
public class test {
public test() {
}
public static void main(String[] args) {
int i = 1;
int i = i++;
System.out.println(i);
int j = 1;
++j;
System.out.println(j);
}
}
我们可以看到原来的i=i++;操作被替换成了int i=i++;,而j=++j;被替换成了++j;,目前我们根据class文件发现了i=i++和j=++j的直接区别,下面我们将根据字节码进行解释。
main方法的字节码如下(建议文章后续操作都要根据此字节码进行观看)
0 iconst_1
1 istore_1
2 iload_1
3 iinc 1 by 1
6 istore_1
7 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
10 iload_1
11 invokevirtual #3 <java/io/PrintStream.println : (I)V>
--------上面的是i的操作,下面的是j的操作----------
14 iconst_1
15 istore_2
16 iinc 2 by 1
19 iload_2
20 istore_2
21 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
24 iload_2
25 invokevirtual #3 <java/io/PrintStream.println : (I)V>
28 return
我们根据字节码一步一步来解释
前提条件当前局部变量表为
局部变量表 | ||||
序号 | 0 | 1 | 2 | |
元素 | this | i | j | |
值 | 0 | 0 |
操作数栈(还是空的)
操作数栈 |
i 值操作过程
1、操作1:iconst_1:将操作数栈放一个int值为1
2、操作2:istore_1:将操作数栈出栈操作,赋值给局部变量表序号为1的元素i,这两部操作相当于我们写的int i=1;操作,如图所示:
3、操作3:iload_1:注意此时和++j的操作不一样了,iload_1表示将局部变量表序号为1的元素值执行入栈操作,将值放到操作数栈。
4、操作4:iinc 1 by 1:表示局部变量表序号1的元素自增加1操作,此时i值为2,具体如图所示:
5、操作5: istore_1:和操作2一样为出栈操作,将操作数栈的值赋给局部变量表序号为1的元素,也就是说 i 值得变化是从0(初始值)-1-2-1的过程最后为1。如图所示
i之后的操作就是输出,不过多解释了
j 值操作过程
1、操作1、2: iconst_1 istore_2:和 i 操作1、2一致,就是int j = 1 ;的过程
2、操作3:iinc 2 by 1:注意此时我们和 i 从操作不一样,这时我们是先进行自增操作,也就是说当前局部变量表的 j 值为2了
3、操作4、5:此时我们再次将局部变量表序号为2的元素值放到操作数栈,然后为 j 进行赋值,操作如图
最后 i 的值为1,而 j 的值为2
题外话:
有趣的是如果我们不进行输出的操作,无论是 i = i++,还是 j = ++j 都会被class反编译成++i / j,但是在字节码角度上来看又完全不同
public class test {
public static void main(String[] args) {
int i=1;
i=i++;
int j=1;
j=++j;
}
}
class反编译后的文件
public class test {
public test() {
}
public static void main(String[] args) {
int i = 1;
++i;
int j = 1;
++j;
}
}
查看这个反编译后的文件,我们竟无法直接查看出 i = i++、 j = ++j 的直接区别,所以贴一下字节码
0 iconst_1
1 istore_1
2 iload_1
3 iinc 1 by 1
6 istore_1
7 iconst_1
8 istore_2
9 iinc 2 by 1
12 iload_2
13 istore_2
14 return
在字节码角度来看又有很大的区别,读者可以根据上述的知识自己解析一下~
博学的刘二胖: 这个应该没有办法监控吧,因为不知道用户是通过什么方式下载
良神: 如果想监控用户选了保存还是取消,要怎么做?
NenoCat: 太强了大佬!
CSDN-Ada助手: 不知道 云原生入门 技能树是否可以帮到你:https://edu.csdn.net/skill/cloud_native?utm_source=AI_act_cloud_native
CSDN-Ada助手: 推荐 Java 技能树:https://edu.csdn.net/skill/java?utm_source=AI_act_java