源代码
public class PlusTest {
public static void main(String[] args) {
int a = 2;
System.out.println(a++ + ++a);
}
}
编译
>javac PlusTest.java
执行
>java PlusTest
6
反汇编
>javap -c PlusTest
Compiled from "PlusTest.java"
public class PlusTest {
public PlusTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_2
1: istore_1
2: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
5: iload_1
6: iinc 1, 1
9: iinc 1, 1
12: iload_1
13: iadd
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
17: return
}
main()的虚拟机指令分析
iconst_2
上面的指令表示先生成一个常量,值为2。
istore_1
上面的指令表示将常量2赋值给第一个变量(在jshell里就是$1)
getstatic
由于System.out.println()其中的System.out其实是java.lang.System中的一个静态的属性,所以这个指令顾名思义,就是获取这样一个静态属性。 这个System.out的类型其实是java.io.PrintStream,这点我们在之前的文章中也说过了,感兴趣的可以查看源码自行了解。
iload_1
上面的指令表示将$1(也就是a)这个变量装到栈空间上。
iinc 1, 1
上面的指令全称应该是iincrease,是a++的指令表示,此时$2=$1+1=3。
iinc 1, 1
再执行一次iinc,这是++a的指令表示,此时$3=$2+1=4。
iload_1
将$3压栈,加到虚拟机栈空间中。
iadd
学过数据结构的栈就应该知道栈的应用——计算后缀表达式。 这个指令就是把栈空间栈顶两个整数弹出栈并求和,$4=$3+$1=2+4=6。
invokevirtual
调用System.out的println(),打印$4的值,输出6。
return
main()返回值为void,使用return结束方法,相当于C/C++中int main()最后的return 0。
结论所以说:a++ + ++a;
的运算过程就是执行a++,再把这个值++a,此时原本栈中的变量还是2,并不受影响,只是新的变量相当于经历了2次+1运算。最终将两个栈中变量相加求和。
还是那句话,最好不要滥用++,导致程序乱七八糟,但如果有什么疑惑,可以打开javap命令去分析一下反汇编指令,一切尽在不言之中。