今天遇到一段程序代码,如下:
int j = 0;
for(int i = 0;i < 100;i++) {
 j = j++;
 System.out.println(j);
}
就是这段程序会输出什么,当时不假思索便认为
输出会是1,2,3,4,5,6,7,8,9,10。
编译运行的结果却是0,0,0,0,0,0,0,0,0,0。即10个零。
百思不得其解。
当时给的解释是i = i++ 和下面这段程序是相同的效果:(记不清楚了)
int i = 0;
int tmp = i;
i = i + 1;
i = tmp;
想想还是比较迷糊,于是回来反编译了一下一些代码,发现一些问题:int i = 0;
i++;
这个反编译出来的是:
   0: iconst_0
   1: istore_1
   2: iinc 1, 1
   5: returnint i = 0;
i = i + 1;
反编译的结果是:
   0: iconst_0
   1: istore_1
   2: iload_1
   3: iconst_1
   4: iadd
   5: istore_1
   6: returnint i = 0;
i = i ++;
反编译的结果是:   0: iconst_0
   1: istore_1
   2: iload_1
   3: iinc 1, 1
   6: istore_1
   7: return从这三段反编译的代码来看,i++ 的效率比 i = i + 1 的效率高出很多。
但是后面两段看起来比较晕。
请大虾指教。

解决方案 »

  1.   

    j=j++ 的意思是先对j进行赋值(此时j仍然为0) 然后j再自加;
    j=j++; 执行后在System.out.println(j);中j的值为0当然输出是0 0 0 0 了  
    如果把j=j++; 改为j=++j;那么先进行++j操作得到j=1;然后输出则得到的是 1 
    就可以得到 1 2 3 4 5 6 7 8 ...的结果
    但是同样在c语言中运行
    main()
    {
    int i,j;
    j=0,i=0;for(i=0;i<100;i++)
    {
    j=++j;
    printf("j=%d ",j);
    }
    }
    和main()
    {
    int i,j;
    j=0,i=0;for(i=0;i<100;i++)
    {
    j=j++;
    printf("j=%d ",j);
    }
    }却得到了相同的结果 1 2 3 4 5 6 7...
      

  2.   

    把程序改一下:                  
                     int j = 0;
    for(int i = 0;i < 10;i++) {
      j++;
     System.out.println(j);
                       System.out.println(i);
    }
    j打印出的就是我们预想的1,2,3,4,5,6,7,8,9,10
    i打印出的却是0,1,2,3,4,5,6,7,8,9
    也就是j++和i++在不同的作用域导致不同的结果了再把程序改一下:
    int j = 0;
    int c=0;
    for(int i = 0;i < 10;i++) {
     c=j++;
     System.out.println(c);
                      }
                实际上这边输出的,其实就是上例的i,也是0,1,2,3,4,5,6,7,8,9
                  
     而                int j = 0;
    int c=0;
    for(int i = 0;i < 10;i++) {
     j=j++;
     System.out.println(c);
                      }
    之所以输出全零是因为,j=j++,右边的j++每次都得到零,自加1,它把零赋给了左边的j!每个循环都是如此!                    
      

  3.   

    同意zj428032(fc) ( ) 信誉:100  
    输出的结果可以理解,但楼主的反编译代码却晕,看不懂!
      

  4.   

    java的编译器搞的鬼!在遇到++和--操作符的时候会重新为原变量分配一块内存空间,以存放原始的值,而在完成了赋值运算之后,就将这块内存释放掉。由于i的原始值存放在后开辟的内存中,这样i=i++后,由于是先赋值,i就会得到i的原始值(存放在新内存中的数椐),而原来内存位置的i自加后只保留在原来的位置,由于此时i指向已经是新开辟出来的内存地址,所以i的值没有发送变化!
    换句话说,
    while(true){
       i=i++;
    }
    永远执行i的值恒等于i的初始值,即使不是0也一样!下面我把过程写一下i=0;//假设此时内存地址为0x12345678
    i=i++;//系统新开内存地址0x99999999,存放i原始值0,然后0x12345678的存放数据+1操作
          //此时0x12345678=1,0x99999999=0,但是上一步是先给值,所以i的内存地址是0x99999999=0;所以i=0,但是,如果是
    i=0;
    i++;
    此时i=1,因为0x99999999处新开辟的内存地址没有给任何引用,所以被丢弃了!i继续使用0x12345678处值
      

  5.   

    这个问题涉及到了运算符的优先级问题。
    ++运算符的优先级比=运算符要高,也就是说,首先计算++,然后计算=那么上面的j=j++;就可以看作是首先计算j++,然后将这个表达式的返回值赋值给j。
    j++进行计算的时候,会让j字加一,也就是从0变成1;
    但是,j++的返回值是0,因为++运算符放在后面时是先取值作为返回值备用,然后自加;
    最后,把这个返回值(也就是0),通过=运算符赋值给j,也就是让j又变成了0。至于你的反汇编……
      

  6.   

    JVM 模拟一个基于stack(堆栈)的 CPU。
    也就是说这个CPU里面的存储器是stack结构的,特点是好像一个大坑,先掉进去的最后才能爬出来。
    那么我们看一下你的反汇编代码。int i = 0;
    i++;
    这个反编译出来的是:
       0: iconst_0 将常数0推入stack
       1: istore_1 从stack中弹出一个值(这个值显然是刚刚推入的0)存储到变量索引为1的位置(也就是我们的i)
       2: iinc 1, 1 将变量索引为1的变量(也就是我们的i)值增加1,现在i变成了1
       5: return 返回int i = 0;
    i = i + 1;
    反编译的结果是:
       0: iconst_0 将常数0推入stack
       1: istore_1 从stack中弹出一个值(这个值显然是刚刚推入的0)存储到变量索引为1的位置(也就是我们的i)
       2: iload_1 将变量索引为1的变量值推入stack,现在stack里面只有一个值: 0
       3: iconst_1 将变量1推入stack,现在stack里面有两个值,依次(推入次序)为: 0, 1
       4: iadd 从stack中弹出两个值进行相加,并将结果推入stack,现在stack里面又剩下一个值: 1 (因为0 + 1 = 1)
       5: istore_1 从stack中弹出一个值(这个值显然是刚刚算出的1)存储到变量索引为1的位置(也就是我们的i),现在i变成了1
       6: return 返回int i = 0;
    i = i ++;
    反编译的结果是:   0: iconst_0 将常数0推入stack
       1: istore_1 从stack中弹出一个值(这个值显然是刚刚推入的0)存储到变量索引为1的位置(也就是我们的i)
       2: iload_1 将变量索引为1的变量值推入stack,现在stack里面只有一个值: 0
       3: iinc 1, 1 将变量索引为1的变量(也就是我们的i)值增加1,现在i变成了1
       6: istore_1 从stack中弹出一个值(这个值应该是前面2的位置推入的0)存储到变量索引为1的位置(也就是我们的i),现在i又变成了0
       7: return 返回
    这就是结果的原因。参考了这个网站:
    http://www.jspcn.net/htmlnews/11049384431711149.html
      

  7.   

    哦,补充一点:上面所提到的值,都是指int类型的。否则bytecode指令会有所不同。
      

  8.   

    for(int i = 0;i < 10;i++) {
     j=j++;
     System.out.println(c);
                      }
    1.j在自增之前将值副给j,此时j还是0,下一次循环又重复了这个过程,所以输出都是0
    2. short j=0;
       j=j+1;//编译通不过,必须强制类型转换
       但是:
       j+=1;//可行的,不管是向类型小的转换都可以
      

  9.   

    上次有人问过,结果应该是很容易理解。
    不过c语言的结果比较让人费解(c语言标准对i=i++这个没有规范,也就是说不同的编译器可以实现不同)
      

  10.   

    謝謝各位的解答。
    基本上已經知道是什麽情況了。i = i++在C中是未定义的情况,可以进行如下操作: 
    1) i++; i = i 
    2)temp = i; i++; i=temp 而Java明確規定了 i = i ++ 是進行第二种操作(據説JVM規範上有,我身邊沒這書,不知是否是這樣),這樣就不能理解為什麽是 0 了 。
      

  11.   

    grant999(民)的说法有问题呀。其中第一个,好像是反的,应该是先自增,但是又把自增后的返回值(因为++在后,所以是原来j的值)赋值给了j。所以j又变回了原来的值。第二个问题,详细讨论可以看这里
    http://community.csdn.net/Expert/topic/4197/4197388.xml?temp=.41914
      

  12.   

    他们说的规定可能是Java Language Specification和Java Virtual Machine Specification这两个文档都在Sun的网站上有。
    http://java.sun.com/docs/index.html最新的Java Language Specification
    http://java.sun.com/docs/books/jls/third_edition/html/j3TOC.html最新的Java Virtual Machine Specification
    http://java.sun.com/docs/books/vmspec/2nd-edition/jvms-java5.html所以,不需要花钱去买了。这东西本来就是免费的。