javap命令行分析(a++ + ++a)的虚拟机指令

源代码

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."<init>":()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命令去分析一下反汇编指令,一切尽在不言之中。

发布了645 篇原创文章 · 获赞 1334 · 访问量 57万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/104626322