源码:
package cn.itcast.jvm.t3.bytecode;
/**
* 从字节码角度分析 a++ 相关题目
*/
public class Demo3_2 {
public static void main(String[] args) {
int a = 10;
int b = a++ + ++a + a--;//10+12=22;22+12=34;
System.out.println(a);//11
System.out.println(b);//34
}
}
字节码:
- main线程开始运行,分配栈帧内存:
- locals=3:局部变量表有3个变量槽。
- stack=2:操作数栈的最大深度为2。
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
2: istore_1
3: iload_1
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。
1)bipush 10:
- 将一个 byte 压入操作数栈(其长度会补齐 4 个字节),类似的指令还有
- sipush 将一个 short 压入操作数栈(其长度会补齐 4 个字节)
- ldc 将一个 int 压入操作数栈
- ldc2_w 将一个 long 压入操作数栈(分两次压入,因为 long 是 8 个字节)
- 这里小的数字都是和字节码指令存在一起,超过 short 范围的数字存入运行时常量池
2)istore_1 - 将操作数栈顶数据弹出,存入局部变量表的 slot 1
3)iload_1 - 将局部变量表的slot 1中的数据读取到操作数栈中
4)iinc 1,1 - 将局部变量表中的solt 1中的数据值加1
5)iinc 1,1
6)iload_1 - 将局部变量表的slot 1中的数据读取到操作数栈中
7)iadd - 将操作数栈中的栈顶的两个数据弹出,并相加,最后将结果压入栈中
8)iload_1 - 将局部变量表的slot 1中的数据读取到操作数栈中
9)iinc 1, -1 - 将局部变量表中的solt 1中的数据值加-1
10)iadd
11)istore_2 - 将操作数栈顶数据弹出,存入局部变量表的 slot 2
所以最后输出的结果为:a=11; b=34;