public static void main(String[] args) {
int a=10;
int b=a++;
int c=++a;
}
在最开始学习Java时我们都知道,第二行代码:int b=a++,是先把变量赋值给b,然后再执行自增。第三行代码:int b=++a;是先对a执行自增,再赋值给c。
下面我们看Java编译的字节码文件来看一下在底层,栈内部这个区别是具体怎么体现的。
经过编译之后会生成.class的字节码文件,我们可以使用以下命令查看字节码文件
javap -v *.class
得到以下结果
Classfile /Users/mengao/IdeaProjects/JavaBook/target/classes/_05_jvm相关/_02_.class Last modified 2022-2-12; size 454 bytes MD5 checksum 5c2f282df67cce412e133bdf41f398da Compiled from "_02_.java" public class _05_jvm相关._02_ minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #3.#21 // java/lang/Object."":()V #2 = Class #22 // _05_jvm相关/_02_ #3 = Class #23 // java/lang/Object #4 = Utf8 #5 = Utf8 ()V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 LocalVariableTable #9 = Utf8 this #10 = Utf8 L_05_jvm相关/_02_; #11 = Utf8 main #12 = Utf8 ([Ljava/lang/String;)V #13 = Utf8 args #14 = Utf8 [Ljava/lang/String; #15 = Utf8 a #16 = Utf8 I #17 = Utf8 b #18 = Utf8 c #19 = Utf8 SourceFile #20 = Utf8 _02_.java #21 = NameAndType #4:#5 // " ":()V #22 = Utf8 _05_jvm相关/_02_ #23 = Utf8 java/lang/Object { public _05_jvm相关._02_(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object." ":()V 4: return LineNumberTable: line 9: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this L_05_jvm相关/_02_; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=1, locals=4, args_size=1 0: bipush 10 2: istore_1 3: iload_1 4: iinc 1, 1 7: istore_2 8: iinc 1, 1 11: iload_1 12: istore_3 13: return LineNumberTable: line 11: 0 line 12: 3 line 13: 8 line 18: 13 LocalVariableTable: Start Length Slot Name Signature 0 14 0 args [Ljava/lang/String; 3 11 1 a I 8 6 2 b I 13 1 3 c I } SourceFile: "_02_.java"
其中的关键部分是main方法里执行的代码:
0: bipush 10
2: istore_1
3: iload_1
4: iinc 1, 1
7: istore_2
8: iinc 1, 1
11: iload_1
12: istore_3
13: return
添加注释:
0: bipush 10 # 把变量10放入操作数栈
2: istore_1 # 把操作数栈里的数存储到槽位编号1的变量上,也就是赋值给变量a,此后a=10
3: iload_1 # 把变量a的值放入操作数栈
4: iinc 1, 1 # 对槽位编号1的变量执行+1,此后a=11
7: istore_2 # 把操作数栈里的内容赋值给槽位编号2的变量上,也就是赋值给变量b,此后b=10
8: iinc 1, 1 # 对槽位编号1的变量执行+1,此后a=12
11: iload_1 # 把槽位编号为1的内容,存储到操作数栈
12: istore_3 # 把操作数栈里栈顶的值赋值给槽位编号为2的变量,也就是赋值给变量c,此后c=12
13: return # 结束
可以看到在经过编译后的字节码文件里的指令集中,就能发现在栈内部的区别。
a++是先把变量放到操作数栈,然后对变量进行++,这时操作数栈存储的还是原来的值,最后把操作数栈里的值赋值给变量b
++a是先把变量a,在槽位里直接+1,然后再把槽位变量a放到操作数栈顶,最后把这个操作数栈顶的值赋值给变量b。



