为什么i=i++后,i的值不变(深入解析)
在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的值不变(深入解析)的更多相关文章
- ListView与.FindControl()方法的简单练习 #2 -- ItemUpdting事件中抓取「修改后」的值
原文出處 http://www.dotblogs.com.tw/mis2000lab/archive/2013/06/24/listview_itemupdating_findcontrol_201 ...
- Sql示例说明如何分组后求中间值--【叶子】
原文:Sql示例说明如何分组后求中间值--[叶子] 这里所谓的分组后求中间值是个什么概念呢? 我举个例子来说明一下: 假设我们现在有下面这样一个表: type name price -- ...
- 后端model传入前端JSP页面中的值判断后再取值
所遇到的问题后端model传入前端JSP页面中的值通过foreach循环内要满足条件才能取值给Div中,我们知道jsp页面中可以直接用EL表达式取值,格式就是${"model中传来的数据&q ...
- MySQL 如何在一个语句中更新一个数值后返回该值 -- 自增长种子竞态问题处理
什么是竞态问题? 假设有一个计数器,首先当前值自增长,然后获取到自增长之后的当前值.自增长后的值有可能被有些操作用来当做唯一性标识,因此并发的操作不能允许取得相同的值. 为什么不能使用使用UPDATE ...
- python执行系统命令后获取返回值的几种方式集合
python执行系统命令后获取返回值的几种方式集合 今天小编就为大家分享一篇python执行系统命令后获取返回值的几种方式集合,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧 第一种情 ...
- c++ xml 解析“后直接跟值问题
c++ xml库相关 要解析内容: <ITEM name="SLSJ"head="SLSJ"/> 代码: GetNodeAttri(subnodes ...
- [BS-00] const限定常量或者变量(初次赋值后),其值不允许被改变
CONST(C中的CONST) const是一个C语言(ANSI C)的关键字,它限定一个变量不允许被改变,产生静态作用.使用const在一定程度上可以提高程序的安全性和可靠性.另外,在观看别人代码的 ...
- EDMX更新实体后出现键值映射问题
近期做项目的EF改版时,在DB(ORACLE)中的表里添加一个新的PK,去除原有的PK. 在DB已添加完成操作,但这时在EDMX里进行从DB更新到EF里,更新完成后就发生如下错误提示: Error 6 ...
- [Shell]Shell调用并获取执行jar包后的返回值
----------------------------------------------------------------- 原创博文,如需转载请注明出处! 博主:疲惫的豆豆 链接:http:/ ...
- vue 解决双向绑定中 父组件传值给子组件后 父组件值也跟着变化的问题
说明: 近日开发中碰见一个很诡异的问题, 父组件动态的修改对象 data 中的值, 然后将这个对象 data 传给子组件, 子组件拿到后将 data 中的值 乘以 100 ,发现父组件中的值也跟着变 ...
随机推荐
- ansible安装php
环境:Centos 7.x 独立php-fpm.conf配置文件 [root@master playbook]# tree php php ├── php-fpm.conf └── php.yml p ...
- C#中RichTextBox字体不统一(中英文)
this.richTextBox1.Font = new System.Drawing.Font("微软雅黑", 12F);// new System.Drawing.Font(& ...
- ABAP Netweaver和Hybris里获得内存使用统计数据
ABAP Netweaver 事物码ST06 Hybris 每隔5秒钟,Hybris Administration console会发起一个到Java后台的AJAX查询请求: 这个5秒的时间间隔定义在 ...
- Jenkins使用分组过滤分类
背景:Jenkins项目过多,通过选项卡的方式过滤需要的项目 1.点击选择卡上的加号 2.填写要分组的名字 3.可选择某个job进行分类,或者使用正则表达式的方式进行分类,楼主是根据正则进行匹配, 4 ...
- The service command supports only basic LSB actions (start, stop, restart, try-restart, reload,force-reload, status)
# service iptables save The service command supports only basic LSB actions (start, stop, restart, t ...
- 转:深入浅出spring IOC中四种依赖注入方式
转:https://blog.csdn.net/u010800201/article/details/72674420 深入浅出spring IOC中四种依赖注入方式 PS:前三种是我转载的,第四种是 ...
- Entity Framework的扩展库
https://github.com/jcachat/EntityFramework.DynamicFilters Provides global & scoped filters for E ...
- arXiv 上传文章过程
arXiv属于预印本服务的一种,是指科研工作者的研究成果还未在正式出版物上发表,而出于和同行交流目的自愿先在学术会议上或通过互联网发布的科研论文.科技报告等文章.与刊物发表的文章以及网页发布的文章 ...
- 手动安装Apache+PHP+MYSQL及环境配置
先准备好软件: Apache官方下载地址:apache_2.0.55-win32-x86-no_ssl.msi,更多版本在这里: php官方下载地址:php-5.0.5-Win32.zip,更多镜像下 ...
- Oracle Like、Instr以及正则表达式
查看测试数据 select * from student; 1. like 在where字句中使用like可以达到模糊查询的效果,常用通配符如下 ▶ %: 使用 % 有三种情况 ① 字段 like ‘ ...