public class test{
public static void main(String[] args){
int i = 0;
for(int j = 0; j < 10; j++){
i = i++;
System.out.println(i);
}
}
}
为什么输出是10个0?
又为什么把i++换作++i又输出1至10呢?
public static void main(String[] args){
int i = 0;
for(int j = 0; j < 10; j++){
i = i++;
System.out.println(i);
}
}
}
为什么输出是10个0?
又为什么把i++换作++i又输出1至10呢?
i++表达式的值是0
这时i++运算以后虽然i的值是1
但是又把i++表达式的值赋给了i
所以i的值永远都是0
等于说是把i=1这一步给屏蔽掉了而++i表达式的值是1
这样i就会一直加1
我一直都是这么理解的
应该去问问gosling,^^
http://community.csdn.net/Expert/topic/3885/3885309.xml?temp=.9122278
因此最后i的值为0
看完这个就应该明白了。
换句话说,
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处值
旧的空间变成了i++ 这个时候i=13 赋值 因为++的执行特性 是先把i以前的值赋出去,然后才改变(就是+1)
所以变成1的i就又被原始数据改回了04抛弃新开辟的空间 则只有原来的空间,i还是0p.s 其实新空间 和原空间的i都是0了吧?
i=++i 加号在前面的时候,就是先加一 ,再使用i
i=i++;”等式左边的i(以下简称左i,位于栈外)等式右边的i(以下简称右i,位于栈内,是左i被推人栈内的一个副本)在“++”定义上确实是先赋值再自增,即i先被赋为0,然后自增为1。
但是在jvm实现的时候,却是先自增再赋值:先将右i及其“++”符推入栈中,然后jvm一看到++时知道这是个后++,所以应该先弹栈赋值然后自增,它以为只要不在栈内给右i自增就行了(因为最后赋值是弹栈赋值,栈外的值改变不会影响到栈内值,即不影响最后赋值),于是先去栈外把左i的值自增,但它没想到栈内外是同一个值,这样做的后果是赋值后用右i的值把已自增为1的左i又赋回了0。
总结:这一问题的出现是由于jvm在遇到“=”时呆板的入栈弹栈操作导致的,弹栈赋值时确实是用了没自增前的值,但是自增操作却自作聪明地先在栈外做了,此时若“=”两边的变量是同一值时(“j=i++”就能够正常工作),弹栈后就导致自增操作白做了。
我是说因为编译器比较规板,把赋值语句i=i++
生成了i入栈,计算表达式,出栈赋值i的三板斧,
但是这里计算表达式不是在栈上计算的!
所以导致一次多余的入栈和弹栈,清除了本来已经计算好的结果你看看iinc的JVM Spec描述
iinc OperationIncrement local variable by constant
Format
iinc
index
const
Operand Stack No change看到了没有,No Change!!!iinc是直接对变量操作的,不是把操作数放到stack计算的,有点特殊是不是?和传统语言不太一样。你在栈上没有计算,正确的过程是你把i的值0放到栈上
然后把i变成1,但是栈上还是0
最后把栈上的0弹出来赋值给i,结果把刚才iinc的结果给冲掉了,i又变成了0
取i 的初值0 ,然后把i++变为1但是由于是i++
所以赋值的时候给的还是i++前的0值,
所以循环结束后i的值还是0;每次循环都是这样当然最后是10个,0了。