举个简单例子:
public class i {
public static void main(String[] args) {
result1();
result2();
}
public static void result1(){
int i=1;
int a=0;
a=i++;
System.out.println(a);
System.out.println(i);
}
public static void result2(){
int i=1;
int a=0;
a=++i;
System.out.println(a);
System.out.println(i);
}
}
输出的结果:
1
2
2
2
而我们在具体的情况下,想要从更底层知道为什么,或者说结果怎么样,我们就可以通过字节码指令来进行获取。
如果这些不够理解,后面还有图示加深理解
字节码加深理解:
/**
* 从字节码角度分析
*/
public class Demo {
public static void main(String[] args) {
int a = 10;
int b = a++ + ++a + a--;
System.out.println(a);//11
System.out.println(b);//34
}
}
如何获取字节码:
首先在当前类界面点击右键:
进入终端后输入javac 后面跟上类java的名字
然后再进行反编译:
javap -v
就可以获取字节码指令了,然后我们就可以一一分析。
字节码:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: bipush 10 //准备一个常量10
2: istore_1 //赋值给 a变量,10到a槽位里
3: iload_1 //将a变量里的数放到操作数栈
4: iinc 1, 1 //直接在槽位上进行自增运算,第一个参数指定槽位,第二个参数指定自增几
7: iinc 1, 1//指令执行优先级
10: iload_1
11: iadd
12: iload_1
13: iinc 1, -1
16: iadd
17: istore_2
18: getstatic #2 // Field
java/lang/System.out:Ljava/io/PrintStream;
21: iload_1
22: invokevirtual #3 // Method
java/io/PrintStream.println:(I)V
25: getstatic #2 // Field
java/lang/System.out:Ljava/io/PrintStream;
28: iload_2
29: invokevirtual #3 // Method
java/io/PrintStream.println:(I)V
32: return
LineNumberTable:
line 8: 0
line 9: 3
line 10: 18
line 11: 25
line 12: 32
LocalVariableTable:
Start Length Slot Name Signature
0 33 0 args [Ljava/lang/String;
3 30 1 a I
18 15 2 b I
分析:
- 注意 iinc 指令是直接在局部变量 slot 上进行自增运算,而不是在操作数栈。
- a++ 和 ++a 的区别是先执行 iload (+槽位号)还是 先执行 iinc
a++是先load再自增,++a是先自增再load
结合图示来理解:
至此,拿捏死死的已经没问题了吧。