针对变量自增问题,使用字节进行解释
变量单纯的使用++的时候代码如下:
public static void method6(){
int i = 10;
i++;
System.out.println(i);
++i;
System.out.println(i);
for(int j = 0;j<10;j++){
}
}
对应的字节码文件如下
0 bipush 10
2 istore_0
3 iinc 0 by 1
6 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
9 iload_0
10 invokevirtual #5 <java/io/PrintStream.println : (I)V>
13 iinc 0 by 1
16 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
19 iload_0
20 invokevirtual #5 <java/io/PrintStream.println : (I)V>
23 iconst_0
24 istore_1
25 iload_1
26 bipush 10
28 if_icmpge 37 (+9)
31 iinc 1 by 1
34 goto 25 (-9)
37 return
可以看到3,13,31的字节码操作都是一样,因此此时++在前和在后是一样的
对应的idea里反编译的代码如下:
public static void method6() {
int i = 10;
++i;
System.out.println(i);
++i;
System.out.println(i);
for(int j = 0; j < 10; ++j) {
}
}
可以看出系统执行的时候都转为了++i进行执行
问题二:自增变量进行赋值操作
给新的变量赋值
public void method7(){
int i = 10;
int a = i++;
int j = 20;
int b = ++j;
System.out.println(b);
System.out.println(a);
}
···
对应的字节码文件如下:
0 bipush 10 //操作数栈里压入10
2 istore_1 //把操作数栈的数据保存到局部变量表,清空栈
3 iload_1 //从局部变量表中拿出10
4 iinc 1 by 1 //把当前栈里的数据加一放会到局部变量表,但是此时并没有出栈
7 istore_2 //此时才会出栈,存储10到一个新的变量上
8 bipush 20 //压入20
10 istore_3 // 出栈保存为一个新的变量
11 iinc 3 by 1 //直接操作局部变量表为21
14 iload_3 //再拿出来放到栈里
15 istore 4 //栈里弹出重新保存
17 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
20 iload 4
22 invokevirtual #5 <java/io/PrintStream.println : (I)V>
25 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
28 iload_2
29 invokevirtual #5 <java/io/PrintStream.println : (I)V>
32 return
idea反编译的结果
@Test
public void method7() {
int i = 10;
int a = i++;
int j = 20;
++j;
System.out.println(j);
System.out.println(a);
}
可以看出赋值操作的关键就是是否提前iload数据到栈里,栈里的数据通过算术操作后很明显不会弹出,原始数据,而是直接把结果
压入局部变量表,然后通过istore操作进行弹出.
此外inc操作比较特殊,对于操作数栈的数据进行操作前不会先弹出数据在操作,而是不弹出数据,进行操作,操作的结果如果在局部变量表理有数据就会直接修改
同理,如下问题也可以得到解释
public void method8() {
int i = 10;
int i = i++;
System.out.println(i);
}
0 bipush 10
2 istore_1
3 iload_1
4 iinc 1 by 1
7 istore_1
8 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
11 iload_1
12 invokevirtual #5 <java/io/PrintStream.println : (I)V>
15 return