Java中变量自增:a++和++a的区别
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."<init>":()V
#2 = Class #22 // _05_jvm相关/_02_
#3 = Class #23 // java/lang/Object
#4 = Utf8 <init>
#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 // "<init>":()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."<init>":()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。