今天偶然呗问到了一个java中自增运算符的问题,涉及到了堆栈,觉得挺有趣的把它记录下来。

int i=0;
      i=i++;
      结果i是多少?
      这是一个经常被提及的问题,答案一直五花八门。
      具体测试一下以说明问题:
      代码1:

  1. public class Test{
  2. public static void main(String[] args){
  3. int i=0;
  4. i=i++;
  5. System.out.println(i);
  6. }
  7. }

结果i依然是0.分析其反编译后的代码:

  1. public static void main(java.lang.String[]);
  2. Code:
  3. 0:   iconst_0     //0放到栈顶
  4. 1:   istore_1    //把栈顶的值保存到局部变量1,也就是i中
  5. 2:   iload_1     //把i的值放到栈顶,也就是说此时栈顶的值是0
  6. 3:   iinc    1, 1  //注意这个指令,把局部变量1,也就是i,增加1,这个指令不会导致栈的变化,也就是说局部变量1,即i此时为1了。
  7. 6:   istore_1     //把栈顶的值(0)保存到局部变量1,也就是让i为0了,所以最后i为0
  8. 7:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  9. 10:  iload_1
  10. 11:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
  11. 14:  return

值得注意到是i被修改了两次,第一次是i++;i变为1,最后一次是i=0;所以结果i是0
代码2:

  1. public class Test2{
  2. public static void main(String[] args){
  3. int i=0;
  4. int j=0;
  5. j=i++;
  6. System.out.println(i);
  7. System.out.println(j);
  8. }
  9. }

这个结果肯定都知道,i是1,j是0.同样看反编译之后的代码:

  1. public static void main(java.lang.String[]);
  2. Code:
  3. 0:   iconst_0
  4. 1:   istore_1     //i=0
  5. 2:   iconst_0
  6. 3:   istore_2     //j=0
  7. 4:   iload_1      //把i的值放到栈顶,也就是说此时栈顶的值是0
  8. 5:   iinc    1, 1  //局部变量1加1,也就是让i++了,此时i已经是1了,上面说过,此指令不会导致栈变化
  9. 8:   istore_2     //把栈顶的值(注意是0)存入局部变量2,也就是j中,所以j=0
  10. 9:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  11. 12:  iload_1
  12. 13:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
  13. 16:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  14. 19:  iload_2
  15. 20:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
  16. 23:  return

很明显可以看出,java是先把i的值取出来放到栈顶,我们可以认为是引入了第三个变量int k=i;然后i++,这时候i为1了,然后让j=k;也就是0.结论,i的++运算是在对j这个变量的赋值之前完成的。

代码3:

  1. public class Test3{
  2. public static void main(String[] args){
  3. int i=0;
  4. int j=0;
  5. j=++i;
  6. System.out.println(i);
  7. System.out.println(j);
  8. }
  9. }

结果大家也都知道,i=1,j=1
看操作过程:

  1. public static void main(java.lang.String[]);
  2. Code:
  3. 0:   iconst_0
  4. 1:   istore_1    //i=0
  5. 2:   iconst_0
  6. 3:   istore_2     //j=0
  7. 4:   iinc    1, 1   //局部变量i加1,这时候i变成1了 。
  8. 7:   iload_1     //把i的值放到栈顶,栈顶的值是1
  9. 8:   istore_2    //j=1
  10. 9:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  11. 12:  iload_1
  12. 13:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
  13. 16:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
  14. 19:  iload_2
  15. 20:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
  16. 23:  return

对比代码2和代码3,关键的差别就是iload_1   个iinc这两条指令的位置变了。

java中i = i++问题的更多相关文章

  1. java中的锁

    java中有哪些锁 这个问题在我看了一遍<java并发编程>后尽然无法回答,说明自己对于锁的概念了解的不够.于是再次翻看了一下书里的内容,突然有点打开脑门的感觉.看来确实是要学习的最好方式 ...

  2. java中的字符串相关知识整理

    字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...

  3. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  4. java中Action层、Service层和Dao层的功能区分

    Action/Service/DAO简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. Action只负责管理,而Service负责实施. DAO只 ...

  5. Java中常用集合操作

    一.Map 名值对存储的. 常用派生类HashMap类 添加: put(key,value)往集合里添加数据 删除: clear()删除所有 remove(key)清除单个,根据k来找 获取: siz ...

  6. java中的移位运算符:<<,>>,>>>总结

    java中有三种移位运算符 <<      :     左移运算符,num << 1,相当于num乘以2 >>      :     右移运算符,num >& ...

  7. 关于Java中进程和线程的详解

    一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...

  8. Java中的进程和线程

     Java中的进程与线程 一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是 ...

  9. Java中的进程与线程(总结篇)

    详细文档: Java中的进程与线程.rar 474KB 1/7/2017 6:21:15 PM 概述: 几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进 ...

  10. 初探java中this的用法

    一般this在各类语言中都表示“调用当前函数的对象”,java中也存在这种用法: public class Leaf { int i = 0; Leaf increment(){ i++; retur ...

随机推荐

  1. datepicker97切换年月日再连续点击下拉中日期的bug出现问题

    解决办法: function wdateOption(fmt){ if(fmt===undefined){fmt="yyyy-MM-dd"} return{ dateFmt:fmt ...

  2. JavaScript Ajax 实现学习

    创建异步对象: function createXmlHttp(){ var xhobj=false; try{ xhobj=new ActiveXObject("Msxml2.XMLHTTP ...

  3. CSS box-flex属性,然后弹性盒子模型简介

    今天做项目的时候发现一个css3的新属性flex 一.什么是flex 它的作用是能够按照设置好的规则来排列容器内的项目,而不必去计算每一个项目的宽度和边距.甚至是在容器的大小发生改变的时候,都可以重新 ...

  4. orcale 之 初识数据库一

    数据库 数据库顾名思义数据的仓库,只不过这个仓库是在计算机的存储设备之中.一般来说,这些数据面向一个组织,部门或者整个企业,这些数据是按照一定的模型进行存放的数据集合,比如对于一个学生的管理系统来说, ...

  5. Scrapy框架学习(三)Spider、Downloader Middleware、Spider Middleware、Item Pipeline的用法

    Spider有以下属性: Spider属性 name 爬虫名称,定义Spider名字的字符串,必须是唯一的.常见的命名方法是以爬取网站的域名来命名,比如爬取baidu.com,那就将Spider的名字 ...

  6. SEO 小技巧汇总

    一.为了提高搜索点击率,还可以   1.为了增加关键词的密度,将关键字隐藏在页面里(将文字颜色定义成与背景颜色一样). 2.在图象的alt注释语句中加入关键字. 如:<IMG SRC=" ...

  7. https如何工作

    一.http 网络协议基于分层架构构建了七层模型,是ISO建立的用于计算机或者通信系统之间的互联的标准体系.下图展示了其中的五层: http被称为超文本传输协议,是互联网上应用最为广泛的一种网络协议, ...

  8. redis(4)事务

    一.事务 一般来说,事务必须满足4个条件,也就是我们常说的ACID: 1)Atomicity 原子性:一个事务中的所有操作要么全部完成,要么全部不完成,不会结束在中间的某个环节.事务在执行过程中发生错 ...

  9. shiro,基于springboot,基于前后端分离,从登录认证到鉴权,从入门到放弃

    这个demo是基于springboot项目的. 名词介绍: ShiroShiro 主要分为 安全认证 和 接口授权 两个部分,其中的核心组件为 Subject. SecurityManager. Re ...

  10. Java面试题之HashMap阿里面试必问知识点,你会吗?

    面试官Q1:你用过HashMap,你能跟我说说它的数据结构吗? HashMap作为一种容器类型,无论你是否了解过其内部的实现原理,它的大名已经频频出现在各种互联网Java面试题中了.从基本的使用角度来 ...