关于i++和++i 的详解

2019-08-27  本文已影响0人  Clark_ZD

闲暇之余,发现自己对于i++和++i的观念变得模糊些许,所以今天又研究了下。
废话不多说,本文参考了一些文章的解释,然后加入自己的实践和阐述。
大佬轻点喷,毕竟新手上路,老司机欢迎指点。
首先利用网上的给出的参考案例,如下:

int i = 1;//1
i = i++;//2
int j = i++;//3
int k = i + ++i * i++;//4
System.out.println(i);//5
System.out.println(j);//6
System.out.println(k);//7

那么上面的输出结果分别是什么呢?
这还不简单,百度一下就知道了?!?!
好吧。
分别是

4
1
3

我承认你对了,但是怎么得出来的呢?
俗话说授人予鱼不如授人予渔

那么接下来我就阐述下我对这个的理解
咱们一行代码一行代码的看
为了大家能方便复制代码,我的行数序号写在后面咯。
第一行 干了什么事情呢?
int i = 1;

图片.png

粗劣的说明就是 局部变量i赋值为1

接着说第二行
i = i++;

图片.png
可能很多人看蒙蔽了,主要是咱手残画的不好,大家还是听我细细道来。
这里大体一共走了四步(当然实际不止4步哈,等会给大家看看源码分析)
①局部变量表中的i为1 被放置到了操作数栈的顶部
②执行了i++
③此时的局部变量的i就变成了2
④操作数栈的栈顶的1被存储到局部变量表 所以这里的2由变成了1
这里的局部变量的i值变化 是 由 1变成2在变成了1

然后说第三行
int j = i++;

图片.png

这一步也大体执行了3步
①将局部变量表中的1 存储到了操作数栈的栈顶 此时栈顶为1
②将操作操作数栈的1赋值到j 此时j为1
③执行i++操作 此时的i就编程了2
这时i的变换是由1变成了2
这时j的变化是空变成了1

最后说说第四行
int k = i + ++i * i++;
由于第三部比较多 所以我每一个大步骤 我都画一张图 大家看看对应值的变化

图片.png
图片.png
图片.png
图片.png
图片.png
图片.png
图片.png

接下来分别说一下这发生了什么
①将局部变量表中的i为2 存储到 操作数栈的 栈顶 为2
②执行 ++i 操作 此时的局部变量表中的 2 变成了 3
③将局部变量表中的3 存储到操作数栈的栈顶 此时栈顶为3 同时之前栈顶的2被压到栈的下面
此时操作数栈由栈顶往下分别是 3 2
④此时的i++ 这个部分 是先从局部变量 存储到操作数栈当中 此时的i还是为 3位存储到 操作数栈的栈顶
同理 之前的栈顶3 和 栈顶下面的2 一次往下压栈
此时操作数栈从上往下分别是 3 3 2
⑤执行i++ 操作 此时的 局部变量表中的i 由之前的3变成了4
⑥接下来执行操作数栈的 2 + 3 * 3 为 11 并且放置到栈顶
⑦将栈顶的值存储到k 此时k为11
所以 i 为 4 j为1 k为11

公司突然要维修电路 拉闸! 回去了 后面再改进下


接上文:
昨天拉闸停电,今天接着根据代码层面说说这个变化过程
首先java文件是

public class Main1 {
    public static void main(String args[]) {
        int i = 1;
        i = i++;
        int j = i++;
        int k = i + ++i * i++;
        System.out.println(i);
        System.out.println(j);
        System.out.println(k);
    }
}

使用javac进行编译

javac .\Main1.java

然后进行反解析

javap -c .\Main1.class

以下链接是关于jvm的指令的详解的文章 阅读的时候可以参考这个哦
https://blog.csdn.net/hudashi/article/details/7062675
最终的结果就是:

public class com.zd.Main1 {
  public com.zd.Main1();
    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_1//将1推送到栈顶
       1: istore_1//将栈顶int类型的数值弹出并存入到第二个本地变量 此时的i为1
       2: iload_1//将第二个int型本地变量推送至栈顶
       3: iinc          1, 1//此指令语法为iinc index const  所以为将这里的i进行加1操作并且放入栈顶 此时的i为2 栈顶为1
       6: istore_1//将栈顶int类型的数值弹出并存入到第二个本地变量 此时的i为1
       7: iload_1//将第一个int型本地变量推送至栈顶 就是把现在的i也就是1推入栈顶
       8: iinc          1, 1//同样的执行加1操作 所以此时的i为2
      11: istore_2//将栈顶的int类型的弹出并存入到本地的第三个变量中就是j当中
      12: iload_1//将本地的第二个变量就是i推入到栈顶
      13: iinc          1, 1//将本地的第二个变量就是i进行加1操作 所以此时的i变成3
      16: iload_1//将本地的第二个int类型的变量加载到栈顶 就是将此时的i就是3放置到栈顶 此时的操作数栈从上往下分别是3 2 
      17: iload_1//将本地的第二个int类型的变量加载到栈顶 就是将此时的i就是3放置到栈顶 此时操作数栈从上往下分别是 3 3 2
      18: iinc          1, 1//对第二个本地变量执行加1操作 也就是i进行加1操作 所以此时i变成了 3+1 = 4
      21: imul//将栈顶两个int类型的进行弹出并相乘操作 就是 3 * 3=9  并且放置结果到栈顶
      22: iadd//将栈顶两个int类型的进行弹出并相加操作就是 9 + 2=11 并且压入栈顶
      23: istore_3//将栈顶的值弹出并存储到第4个本地变量也就是k 所以此时的k为11
      24: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      27: iload_1
      28: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      31: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      34: iload_2
      35: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      38: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      41: iload_3
      42: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      45: return
      24: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      27: iload_1
      28: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      31: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      34: iload_2
      35: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      38: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      41: iload_3
      42: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      45: return
}

我已经将上面的重要代码每一行写入了自己的理解注释可以一行行的看
欢迎大哥们指出错误

上一篇下一篇

猜你喜欢

热点阅读