欢迎来到HugNew-拥抱变化,扫一扫右边二维码关注微信订阅号:Martin说 或 加QQ群:427697041互相交流,Stay hungry, Stay foolish.

深入理解自增自减运算符a=a++和a=++a

J2SE Martin 4024℃ 1评论

首先贴一个非常简洁却不简单的代码:

Java(jdk1.6) 代码 (C++代码类似,采用GNU的g++编译器)

public class Test{
    public static void main(String[] args){
        int a=0;
        a = a++;
        System.out.println(a);
    }
}

思考一个问题,这个程序a的输出是多少呢?

… …

最开始的想法是这样的,++自增运算符在这里是后缀式,应该是a赋值给a之后,a再自增一次,即首先a=a,然后a++(a=a+1).如此,最后a的输出值应该是1.

但是,不管是C++(g++编译器)还是Java(jdk1.6),运行的结果让我很惊讶,a的输出为0!这是为什么?csufox经过一段时间的思考,得出了以下的一些认识.

搜索了很多资料,网上有人给出的解释大致如下:++运算符的优先级高于赋值运算符,在程序运行a++时,a的值首先是赋值给一个拷贝或者说临时变量(按值传递,底层实现),即temp=a(即temp=a=0),然后a执行自增运算(运算后a的值为1),最后将这个拷贝(此时拷贝的值为0)作为(a++)整体的值赋值给a(赋值后a的值有重新从1变为0),所以最终的a的值输出为0.即a=a++;语句等价于 a=(temp=a,a+=1,temp);

但是这个解释实在是牵强,底层依然不清楚是具体怎么做的,为什么需要有临时变量?并不能让人信服.下面csufox将从Java的字节码指令来更清楚地了解其细节.

用javap命令反编译上述代码的字节码文件,得到如下信息(附解释):

D:\java>javap -c Test
Compiled from "Test.java"public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return 

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0         //将常量'0'push入操作数栈(operand stack,与普通栈不同)
   1:   istore_1         //将常量'0'存储到栈(注意不是堆,局部变量存储在栈中)
   2:   iload_1          //将常量'0'载入到操作数栈
   3:   iinc    1, 1     //在栈中将a增1,a从'0'变为'1'
   6:   istore_1         //在操作数栈中将常量''重新存储到栈,a从'1'变回'0'
   7:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   10:  iload_1
   11:  invokevirtual   #3; //Method java/io/PrintStream.println:(I)V
   14:  return 

}

而看看a=++a;的字节码指令:(该代码的a的输出显然是1)

Code:
 0:   iconst_0
 1:   istore_1
 2:   iinc    1, 1      //不同点*
 5:   iload_1          //不同点*
 6:   istore_1
 7:   getstatic
 10:  iload_1
 11:  invokevirtual
 14:  return

我们可以看出不同点就是一个是先载入再自增运算;一个是先自增运算后,再载入新值.

综上可知,iinc字节码指令每次执行时都是从栈中直接执行,而不是在操作数栈中执行.

  1. 在i=i++的情况下,变量a已经在栈中改变,但是在操作数栈中依然保留原值;
  2. 在i=++i的情况下,变量a已经在栈中改变,但是在操作数栈中载入的是改变后的新值.

以上是Java对代码输出的解释.C++的解释依然不得而知,将来csufox准备看汇编吧.

参考:

Java字节码及字节码指令: http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/

Java虚拟机规范: http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html

转载请注明:HugNew » 深入理解自增自减运算符a=a++和a=++a

喜欢 (1)or分享 (0)
发表我的评论
取消评论

表情
(1)个小伙伴在吐槽
  1. public class Test { public static void main(String[] args) { int a = 0; /** * 先运行再加 */ //System.out.println(a++); // 0 //System.out.println(a); // 1 //========================= /** * 先加再运行 */ //System.out.println(++a); //1 // System.out.println(a); //1 } }
    匿名2015-01-19 00:51 回复