zoukankan      html  css  js  c++  java
  • Java 趣事之 a=a++ 和 a=++a(转)


    转自https://blog.csdn.net/LovePluto/article/details/81062176


    如果问 a++ 和 ++a 的区别,估计很多都能回答上来。a++ 是先取 a 的值再自增 。而 ++a 刚好相反,是先自增再取 a 的值。这里有点编程基础都可以理解,不做过多解释,但在 Java 里面事情就真的这么简单吗?

    int a = 1;
    a = a++;
    System.out.println(a);

    输出是1

    凭借自己所学,在不测试的情况下,你能给出答案吗?

    第一次看见这个问题的时候,想当然的认为答案是:2。但残酷的事实告诉我,答案是:1。当时面对这个结果我是无法接受的,网上疯狂搜索这个答案的解释。限于当时知识的水平,只记住了这个结论,至于推导这个结论那些指令,一个也不能理解。今天看书遇见数据操作,就又想起了这个问题,就根据自己的知识水平,重新推导这个过程。

    首先用 IDEA 打开生成的 class 文件。

    很直观的告诉我们结果为 1 ,但这段代码只解释了 result,而没有解释 why ,继续用 javap -c 这个命令,结果如图。

    以第一次遇见这道题的水准,勉强能看懂第一步的 Java 代码,第二步的指令就彻底看不懂了。而现在我可以从这些指令里面分析结果了(这里需要分析的就前五行命令,后面指令为打印输出)。

    iconst_1

    将常量 1 压入操作数栈。这个操作是 int 值为 1~5 的时候。如果是 -128~127 这个范围是用的 bipush x (x 为实际数值)。 -2^15~2^15-1 这个范围是使用的 sipush x 这个命令(同上)。 -2^31~2^31-1 这个范围是使用的 ldc 这个命令。

    istore_1

    弹出操作数栈顶的数(此时为 1)并赋值给局部变量第一个元素即索引为 1 的 a。局部变量是采用的数组形式,索引为 0 的是 main() 的参数 args 。

    iload_1

    把局部变量索引为 1 的变量(这里是 a)压入操作数栈,此时栈顶元素为 1 。

    incc 1,1(关键)

    把局部变量索引为 1 的数加 1 ,此时 a 的值为 2。注意:这个结果没有压入操作数栈。

    istore_1

    弹出栈顶的元素(此时为 1)赋值给 a ,覆盖 a 为 2 的结果。

    整个过程大致就是这样,来一幅图解释吧。


    这个问题解决了,那么下面这段代码就好理解了。

    int a = 1;
    a = ++a;
    System.out.println(a);
    输出是2
    直接上截图吧

    仔细对比一下,你会发现,两段代码的指令一模一样,但执行顺序有一点点区别, iinc 和 iload_1 这两个命令的执行顺序变化了一下位置。
    是先给索引为1的变量(这里是a) 加了1,再把这个数压入操作数栈,最后再赋值回索引为1的变量

    自己记录

    iconst 获得初始值加入操作栈
    istore 初始值赋值给a
    iload 把a加入操作数栈
    incc 1,1 把局部变量的a+1
    istore 再把操作数栈的赋值给a

  • 相关阅读:
    tomcat配置通过域名直接访问项目首页步骤
    kafka配置参数
    nginx平滑升级
    redsi一主两从三哨兵
    kill
    lelnet爱一直在
    在linux中查看进程占用的端口号
    监控redis
    老猿学5G随笔:RAN、RAT以及anchor移动性锚点的概念
    老猿学5G随笔:5G网元功能体NF以及NF之间的两种接口--服务化接口和参考点
  • 原文地址:https://www.cnblogs.com/Esquecer/p/11506776.html
Copyright © 2011-2022 走看看