从字节码来说明i++与++i到底有什么不同

作者: 赵荆州 | 来源:发表于2019-08-20 10:24 被阅读2次

    看字节码之前需要先了解相关概念,如栈帧、操作数栈、局部变量表。
    栈帧是JVM中很重要的一个概念,因为JVM是基于栈的架构。一个方法的调用其实就是栈帧入栈出栈的过程。栈顶栈帧就是当前方法调用。
    一个栈帧中包含:

    1. 局部变量表
    2. 操作数栈
    3. 动态链接
    4. 方法返回地址

    这里i++、 ++i涉及到的就是局部变量表和操作数栈。具体信息可参考:《Java虚拟机规范》

    局部变量表存储的是方法的参数以及内部定义的变量的值,操作数栈也是一个栈结构,用来执行方法中的指令。

    好了,来看一个代码片段:

    class Scratch {
    
        public static void main(String[] args) {
            int i=0,j=0,m=0;
            j = i++;
            m = ++i;
        }
    }
    

    为了不产生其他多过信息,这里只写了关键代码。
    首先可以通过javac 将源码编译成class:

    javac scratch.java
    

    执行完成后将看到Scratch.class 文件,通过javap命令查看字节码:

    javap -c Scratch > scratch.txt
    

    为了方便查看将结果输出到了scratch.txt,打开此文件将看到如下信息:

    Compiled from "scratch.java"
    class Scratch {
      Scratch();
        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_0
           1: istore_1
           2: iconst_0
           3: istore_2
           4: iconst_0
           5: istore_3
           6: iload_1
           7: iinc          1, 1
          10: istore_2
          11: iinc          1, 1
          14: iload_1
          15: istore_3
          16: return
    }
    
    

    关注main方法 0-5,可以发现对应的是:

     int i=0,j=0,m=0;
    

    主要是声明变量并初始化为0。我们可以发现下划线后面跟了一个数字,这里应该代表的是变量在局部变量表中的位置。
    i:1
    j:2
    m:3

    再关注main方法:6、7、10:
    iload_1 表示将局部变量表中位置1的数据放入操作数栈中(这里对应的是i,此时i的值为0)然后pop出来赋值给j。然后再将i自增iinc。最后istore_2存储j到局部变量表中。
    操作完成后i=1,j=1。
    最后关注main方法:11、14、15:
    iinc首先自增i,然后iload_1将局部变量表中位置1的数据放入操作数栈中(这里对应的是i,此时i的值为2)然后pop出来赋值给m。最后istore_3存储m到局部变量表中。
    操作完成后i=2,j=1,m=2。

    这就是为什么大家都说,i++是先赋值后自增,而++i是先自增后赋值的原因。

    这里要说明的是,如果是单独的i++、++i是没有什么区别的。

    相关文章

      网友评论

        本文标题:从字节码来说明i++与++i到底有什么不同

        本文链接:https://www.haomeiwen.com/subject/lrdusctx.html