A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

© hejinzhong 中级黑马   /  2014-8-17 22:05  /  1715 人查看  /  11 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

在Java中下面的两个程序的运行后i的值是不一样的,这一点和C或者C++有所不同,关键在于Java虚拟机的实现及其指令的特点。
(Java语言规范中的Java虚拟机规范)

  1. public class Inc{
  2.   public static void main(String argv[]){
  3.     int i=0;
  4.     i=i++;
  5.   }
  6. }
  7. 运行之后i=0。奇怪?为什么呢?
复制代码

对程序进行反汇编(注意不是反编译,如果是反编译得到的是Java代码不是Java汇编代码)

  1. $0 iconst_0 //push 'int' constant 0
  2. $1 istore_1 //store 'int' into local variable #1
  3. $2 iload_1 //load 'int' from local variable #1
  4. $3 iinc *1 1 //increment local variable by constant
  5. $6 istore_1 //store 'int' into local variable #1
  6. $7 return //return 'void' from method
复制代码

下面解释其中的Java汇编指令的含义
(1)$0 iconst_0
iconst_<i> 作用是将常数i压入操作数栈,这里是0
(2)$1 istore_1
istore_<n> n是指当前局部变量帧中局部变量的索引,这里的1说明是第一个变量(我们的程序中只有一个变量,当然是第一个),指令从操作数栈顶弹出一个整型数放到指定的变量中,因此局部变量i的值被赋值为0。由此看到,这个和我们在8086汇编语言中看到的很不一样,在80x86中用MOV指令就可以了
(3)$2 iload_1
iload_<n> n是指当前局部变量帧中局部变量的索引,这里的1说明是第一个变量;指令把从变量取出的值压入操作数栈
(4)$3 iinc *1 1
iinc index const 该指令中index是指当前局部变量帧中局部变量的索引,const是说明在这个变量上加多少,在这条指令中将i加1。这条指令不影响操作数栈。
(5)$6 istore_1
关键在于这儿,该指令又从操作数栈顶弹出一个整型数放到指定的变量中;刚才第三条指令已经将0压入堆栈,所以弹出后赋值给i,结果i的值还是保持0不变。
(6)$7 return
方法返回,这个就不多说了


  1. public class Inc{
  2.   public static void main(String argv[]){
  3.     int i=0;
  4.     i=++i;
  5.   }
  6. }
  7. 运行之后i=1
复制代码

程序反汇编的结果

(1)$0 iconst_0 //push 'int' constant 0
//将0压入操作数栈
(2)$1 istore_1 //store 'int' into local variable #1
//从操作数栈顶弹出0存放在第一个变量i中
(3)$2 iinc *1 1 //increment local variable by constant
//i的值加1,所以i=1
(4)$5 iload_1 //load 'int' from local variable #1
//将第一个变量i的值压入操作数栈
(5)$6 istore_1 //store 'int' into local variable #1
//从操作数栈顶弹出值到i,所以i=1
(6)$7 return //return 'void' from method
//返回

评分

参与人数 1技术分 +1 收起 理由
格子、 + 1 很给力!

查看全部评分

11 个回复

倒序浏览
看看                           
回复 使用道具 举报
没看懂。。。
回复 使用道具 举报

没关系,只是说明++在内存中的运算过程,帮助解释一些程序结果的现象。完全可以不知道
回复 使用道具 举报
hejinzhong 发表于 2014-8-17 22:09
没关系,只是说明++在内存中的运算过程,帮助解释一些程序结果的现象。完全可以不知道 ...

呵呵,多谢分享经验。收藏个先。
回复 使用道具 举报
来学习拉
回复 使用道具 举报
这个其实和++关系不大,而是Java中赋值运算符的特点:=右边的表达式求值过程必须全部完成,才会把值赋给=左边的变量。
i=i++; =右边的i++的求值过程包括3件事:i++的表达式值为i,i自增1,i自增1后的值放回i所在的内存位置。只有这3件事全部做完之后,才会把i++表达式的值0赋给=左边的i,因此i=i++结果为0

i=++i; =右边的++i的求值过程包括3件事:i自增1,i自增1后的值放回i所在的内存位置,++i的表达式值为自增后的i。只有这3件事全部做完之后,才会把++i表达式的值1赋给=左边的i,因此i=++i结果为1
回复 使用道具 举报
fantacyleo 发表于 2014-8-18 01:42
这个其实和++关系不大,而是Java中赋值运算符的特点:=右边的表达式求值过程必须全部完成,才会把值赋给=左 ...

嗯,是这么回事,上面说的是内存中如何完成这个道理,可以看下
回复 使用道具 举报
牛人啊,真佩服
回复 使用道具 举报
fantacyleo 发表于 2014-8-18 01:42
这个其实和++关系不大,而是Java中赋值运算符的特点:=右边的表达式求值过程必须全部完成,才会把值赋给=左 ...

我一直认为,i++是先赋值,再自加,++i是先自加再赋值,看来java的基础也不简单呀。
回复 使用道具 举报
好复杂的样子
回复 使用道具 举报
そ花痕ゐ蝶梦 发表于 2014-8-18 20:24
我一直认为,i++是先赋值,再自加,++i是先自加再赋值,看来java的基础也不简单呀。 ...

这其实是简单了。一个复杂但确定的过程,和一个简单但模棱两可的过程相比,还是前者好一点
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马