在Java中,运行以下代码:

         int i=10;
i=i++;
System.out.println(i);

得到的结果仍然为10,为什么呢?理论上,运算的过程不应该是i首先把10取出来,赋值给i,然后i再自增1,结果不该是11吗?

原因还是要从反编译得到的汇编源码看起。在cmd窗口,输入命令javap -c Demo(Demo是class的文件名),可以得到反编译的汇编源码,

下面我们一步步来,先将两行简单的代码反编译一下。

         int i=10;
int j=9;

上述两行代码的反编译结果是

        0: bipush        10      //将常量10压入操作数栈 
2: istore_1 //将操作数栈顶元素(10)弹出,存入局部变量位置1处
3: bipush 9 //将常量9压入操作数栈
5: istore_2 //将操作数栈顶元素(9)弹出,存入局部变量位置2处
6: return

上下代码可以很简单的对应起来,可以初步看出,赋值语句在汇编其实是有两步,第一步压栈(操作数栈),第二部(出栈并存储至局部变量处)。

为了进行验证,再多加一行代码,如下

         int i=10;
int j=9;
j=i;

同样,反编译看汇编如下:

        0: bipush        10
2: istore_1
3: bipush 9
5: istore_2
6: iload_1
7: istore_2
8: return

很明显的可以看到,j=i这一句,并不是直接把局部变量位置1的值赋值给局部变量2,而是先压入操作数栈,再弹出存储在局部变量位置2处!

下面我们把最开头的i=i++进行一下反编译,得到的结果如下。

 public class Demo {
public Demo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return public static void main(java.lang.String[]);
Code:
0: bipush 10 //将常量10压入操作数栈
2: istore_1 //将操作数的栈顶元素(10)出栈,存入局部变量表1的位置处(这两句话完成了i=10的赋值操作)
: iload_1 //将局部变量表1位置的值压入操作数栈
4: iinc 1, 1 //局部变量表1位置的值自增1
: istore_1            //重新将操作数栈顶的值(10)出栈存入局部变量表1的位置处
8: return
}

只需要从第10行看起就可以了。

可以很明显的看到,自增过程是发生在压栈和出栈中间,所以最后出栈的值会把自增的结果覆盖,导致自增其实是没有作用的。

其实还可以得出一个结论,就是自增和普通的运算的步骤是不同的。自增是直接在局部变量区加1,而运算要进行压栈和出栈操作。

为了验证这句最关键的话,我们把下面代码进行一次反编译。

         int i=10;
i++;
i=i+1;

得到的反编译结果如下:

        0: bipush        10
2: istore_1
3: iinc 1, 1
6: iload_1
7: iconst_1
8: iadd
9: istore_1
10: return

这下很明显了,i++就只有一句话,iinc    1,1,代表在局部变量位置1处的值自增1,而i=i+1则是先把局部变量1位置处的值压栈,再把常量1压栈,再相加出栈,一共四句话!

因此,从内存的角度来看,i=i+1和i++是不同的,也就是说:

i=i++这句话与i=i=i++是不等价的!!!

明白了这个道理,我想再看这个题应该就没有那么恶心了!

为什么i=i++后,i的值不变(深入解析)的更多相关文章

  1. ListView与.FindControl()方法的简单练习 #2 -- ItemUpdting事件中抓取「修改后」的值

    原文出處  http://www.dotblogs.com.tw/mis2000lab/archive/2013/06/24/listview_itemupdating_findcontrol_201 ...

  2. Sql示例说明如何分组后求中间值--【叶子】

    原文:Sql示例说明如何分组后求中间值--[叶子] 这里所谓的分组后求中间值是个什么概念呢? 我举个例子来说明一下: 假设我们现在有下面这样一个表: type        name price -- ...

  3. 后端model传入前端JSP页面中的值判断后再取值

    所遇到的问题后端model传入前端JSP页面中的值通过foreach循环内要满足条件才能取值给Div中,我们知道jsp页面中可以直接用EL表达式取值,格式就是${"model中传来的数据&q ...

  4. MySQL 如何在一个语句中更新一个数值后返回该值 -- 自增长种子竞态问题处理

    什么是竞态问题? 假设有一个计数器,首先当前值自增长,然后获取到自增长之后的当前值.自增长后的值有可能被有些操作用来当做唯一性标识,因此并发的操作不能允许取得相同的值. 为什么不能使用使用UPDATE ...

  5. python执行系统命令后获取返回值的几种方式集合

    python执行系统命令后获取返回值的几种方式集合 今天小编就为大家分享一篇python执行系统命令后获取返回值的几种方式集合,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧 第一种情 ...

  6. c++ xml 解析“后直接跟值问题

    c++ xml库相关 要解析内容: <ITEM name="SLSJ"head="SLSJ"/> 代码: GetNodeAttri(subnodes ...

  7. [BS-00] const限定常量或者变量(初次赋值后),其值不允许被改变

    CONST(C中的CONST) const是一个C语言(ANSI C)的关键字,它限定一个变量不允许被改变,产生静态作用.使用const在一定程度上可以提高程序的安全性和可靠性.另外,在观看别人代码的 ...

  8. EDMX更新实体后出现键值映射问题

    近期做项目的EF改版时,在DB(ORACLE)中的表里添加一个新的PK,去除原有的PK. 在DB已添加完成操作,但这时在EDMX里进行从DB更新到EF里,更新完成后就发生如下错误提示: Error 6 ...

  9. [Shell]Shell调用并获取执行jar包后的返回值

    ----------------------------------------------------------------- 原创博文,如需转载请注明出处! 博主:疲惫的豆豆 链接:http:/ ...

  10. vue 解决双向绑定中 父组件传值给子组件后 父组件值也跟着变化的问题

    说明: 近日开发中碰见一个很诡异的问题,  父组件动态的修改对象 data 中的值, 然后将这个对象 data 传给子组件, 子组件拿到后将 data 中的值 乘以 100 ,发现父组件中的值也跟着变 ...

随机推荐

  1. MSSQL复制分发对异构数据库之间大容量数据分发造成异常

    由于历史遗留的问题,现有的架构中存在采用MSSQL的复制分发功能,从Oracle发布数据到MSSQL. 关于这项发布的实现原理,官方表述如下: Oracle 事务发布是通过使用 SQL Server ...

  2. php程序员发展建议

    2017PHP程序员的进阶之路 又是一年毕业季,可能会有好多毕业生即将进入开发这个圈子,踏上码农这个不归路.根据这些年在开发圈子总结的LNMP程序猿发展轨迹,结合个人经验体会,总结出很多程序员对未来的 ...

  3. c++的bind1st()与bind2nd() 二元算子转一元算子

    bind1st()和bind2nd()是两个函数,用于将二元算子转成一元算子. 何谓二元算子? 比如< > =等等这些就是二元算子,即需要两个操作数的运算符. 何谓一元算子? 比如++ - ...

  4. GitLab-Runner 安装配置

    https://docs.gitlab.com/runner/install/linux-repository.html 直接看官方教程 systemctl status gitlab-runner. ...

  5. April 8 2017 Week 14 Saturday

    Life is the art of drawing without an eraser. 人生如画,落笔无悔. Yesterday I watched a film from Japan, Afte ...

  6. SPOJ - LIS2 Another Longest Increasing Subsequence Problem

    cdq分治,dp(i)表示以i为结尾的最长LIS,那么dp的递推是依赖于左边的. 因此在分治的时候需要利用左边的子问题来递推右边. (345ms? 区间树TLE /****************** ...

  7. 2017.11.15 JavaWeb的学生体质管理系统

    (11)案例-----学生身体体质信息管理系统的开发 11.1 功能划分: 1.添加记录模块:完成向数据库添加新纪录 2.查询记录模块:完成将数据库的记录以网页的方式显示出来,一般采用有条件的查询 3 ...

  8. 20145238-荆玉茗 《Java程序设计》第8周学习总结

    20145238 <Java程序设计>第8周学习总结 教材学习内容总结 第15章 通用API 15.1.1 ·java.util.logging包提供了日志功能相关类与接口,使用日志的起点 ...

  9. Mac 修改用户环境变量

    Mac 修改用户环境变量 sudo vim ~/.bash_profile

  10. Fluent经典问题答疑

    原文链接1 原文链接28 什么叫边界条件?有何物理意义?它与初始条件有什么关系? 边界条件与初始条件是控制方程有确定解的前提. 边界条件是在求解区域的边界上所求解的变量或其导数随时间和地点的变化规律. ...