Java中前置++与后置++的深入学习

前些天看到一篇关于“毒代码”的文章(https://www.jianshu.com/p/3d7dfbfec566),文章的内容还不错,不过有一个问题始终觉得解释的不够透彻,问题如下

关于result = num++和result = ++num的问题,我想早在大学时,老师已经都讲臭了,前置++先自加后赋值,后置++先赋值后自增。

所以当笔者第一眼看到上面那个问题的时候,第一反应是输出99,因为很自然的会觉得 num = num++ 会被分解为:

1:num = num;

2:num++;两步

也就是说将0赋值给num,然后num自增为1,如此循环,但是事实却不是这样,上面的结果为0!

我们注意这里两个表达式的区别 result = num++ 和 num = num++ 这两种写法可是完全不一样的,至于怎么不一样继续往下看。

看了文章中的解释,感觉也是云里雾里,为什么num++没起作用?为什么++后num值没变?难道上学的时候老师说的是错的?

带着这些问题,我们来看下生成的字节码,分析一下,前置++和后置++过程中,JVM究竟做了什么。

首先java代码

public class TestMainClass1 {
    public static void main(String[] args) {
        int num=0;
        num = num++;
        System.out.println(num);
    }
}

public class TestMainClass1 {
    public static void main(String[] args) {
        int num=0;
        num = ++num;
        System.out.println(num);
    }
}

javac生成字节码后,通过javap -c 查看

public class com.aurora.test.TestMainClass1 {
  public static void main(java.lang.String[]);
    Code:
       0: iconst_0    // 整数0入栈
       1: istore_1    // 将0弹出栈,并存储到局部变量1
       2: iload_1    // 将局部变量1的值0入栈
       3: iinc          1, 1    // 局部变量1增加1,值变为1,不操作栈
       6: istore_1    // 0出栈,并存储到局部变量1
       7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: iload_1
      11: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      14: return
}


public class com.aurora.test.TestMainClass1 {
  public static void main(java.lang.String[]);
    Code:
       0: iconst_0    // 整数0入栈
       1: istore_1    // 将0弹出栈,并存储到局部变量1
       2: iinc          1, 1    // 局部变量1增加1,值变为1,不操作栈
       5: iload_1    // 将局部变量1的值1入栈
       6: istore_1    // 1出栈,值存储到局部变量1
       7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      10: iload_1
      11: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
      14: return
}

可以看到区别就是iload和iinc这两个操作顺序的问题,

后置++在iinc增加局部变量的值后,又从操作栈中将变量值istore回了局部变量中,等于iinc白加了。

而前置++是先修改局部变量值,然后局部变量入栈,最后出栈存入局部变量,这一套下来,局部变量的值是变了的。

单纯的文字可能还不太好理解,这里让我这个灵魂画手用图表示下(非战斗人员请迅速撤离):

前置++我就不画了(我画的闹眼睛),本质就是先iinc自增,然后将自增后的值入栈,然后再出栈存入局部变量表。

那么再回到  result = num++ 和 num = num++ 的问题,第一种是赋值给了新变量,第二种是赋值给了num,也就是图中画的那种操作。赋给新变量后,num不会被覆盖,而赋值给num自身的话,因为num自增后结果被出栈的值0给覆盖了,所以num最后还是0.

下面还有几篇文章,也从不同角度讲了这个问题,可以参考看下

1、https://blog.csdn.net/qiaoquan3/article/details/52832640?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.control

2、https://www.cnblogs.com/thiaoqueen/p/8466359.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值