如下java代码最后输出的a、b的值分别是多少
public class Demo3_2 { public static void main(String[] args) { int a=10; int b = a++ + ++a + a--; System.out.println(a);//? System.out.println(b);//? } }
我们用javap反编译工具查看下类的字节码.
javap -v Demo3_2.class 其中main方法的字节码指令树下:
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: 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 32: 0 line 33: 3 line 34: 18 line 35: 25 line 36: 32 LocalVariableTable: Start Length Slot Name Signature 0 33 0 args [Ljava/lang/String; 3 30 1 a I 18 15 2 b I
stack=2 表示栈桢中操作数栈的最大深度为2,locals=3表示局部变量表有3个槽位。槽位0是args ,也就是main方法的入参,槽位1和2分别对应局部变量a和b
我们来分析下,这段源码生成的字节码指令:
bipush 10 执行引擎读取到该指令,将数字10压入操作数栈
istore_1 执行引擎将操作数栈中的值弹出,放入到局部变量表1号槽位,此时1号槽位的值为10
iload_1 执行引擎将局部变量表1号槽位的值压入操作数栈,此时操作数栈中存放的第一个值为10
iinc 1,1 执行引擎将局部变量表1号槽位变量值加1,此时1号槽位的值变为11
iinc 1,1 执行引擎将局部变量表1号槽位变量值加1,此时1号槽位的值变为12
iload_1 执行引擎将局部变量表1号槽位的值压入操作数栈,此时操作数栈中存放的第二个值为12
iadd 执行引擎执行将操作数栈的两个数字相加得到22【10+12】,此时操作数栈中只留下一个值22
iload_1 执行引擎将局部变量表1号槽位的值压入操作数栈,此时操作数栈中存放的第二个值为12
iinc 1,-1 执行引擎将局部变量表1号槽位变量值减1,此时1号槽位的值变为11
iadd 执行引擎将操作数栈的两个数字相加得到34【22+12】,此时操作数栈中只留下一个值34
istore_2 执行引擎将操作数栈中值弹出,放入局部变量表2号槽位,此时2号槽位的值为34
...
因此,最终的结果是:a的值为11,b的值为34
经过分析,我们发现了 i++和++i 在字节码层面上的不同:
i++ : 先执行iload (将局部变量表slot中的变量压入操作数栈) ,再执行iinc 1,1(局部变量表slot槽中变量自加1)
++i : 先执行iinc 1,1(局部变量表slot槽中变量自加1) ,再执行iload (将局部变量表slot中的变量压入操作数栈)
Copyright © 叮叮声的奶酪 版权所有
备案号:鄂ICP备17018671号-1