前置++和后置++ 运算的详解及实例代码
一般认为前置++是先将变量的值加1,然后使用加1后的值参与运算;而后置++是先使用该值参与运算,然后再将该值加1。
先看第一个例子:
packagetest; publicclassPlus_Test01{ publicstaticvoidmain(String[]args){ inti=100; i=i++; System.out.println(i); } }
猜猜结果是什么?
接着看第二个:
packagetest; publicclassPlus_Test02{ publicstaticvoidmain(String[]args){ intk=100; while(true){ if(k++>100){ //System.out.println(k); break; } System.out.println(k); } } }
猜猜结果是什么?
实际上,不管是前置++,还是后置++,都是先将变量的值加1,然后才继续计算的。二者之间真正的区别是:前置++是将变量的值加1后,使用增值后的变量进行运算的,而后置++是首先将变量赋值给一个临时变量,接下来对变量的值加1,然后使用那个临时变量进行运算。
对于如下代码片段(前置++):
inti=1;
intj=++i*5;
实际第二句上相当于:
i+=1;//将i加1
j=i*5;//将加1后的值与之进行计算,此结果为:10
而对于如下代码片段(后置++):
inti=1;
intj=i++*5;
第二句上相当于:
inttemp=i; //将i赋值给一个临时变量
i+=1; //将i加1
j=temp*5; //将临时变量与之计算,此结果为:5
对于第一个例子,相当于:
inttemp=i;
i+=1;
i=temp;//
所以结果应该为不变的,即100。
第一个例子的汇编代码为:
publicstaticvoidmain(java.lang.String[]); descriptor:([Ljava/lang/String;)V flags:ACC_PUBLIC,ACC_STATIC Code: stack=2,locals=2,args_size=1 0:bipush100 2:istore_1 3:iload_1 4:iinc1,1//localvar中第二个加1 7:istore_1//保存至localvar 8:getstatic#16//Fieldjava/lang/System.out:Ljava/io/PrintStream; 11:iload_1//加载的参数为栈中的第二个,即仍然为100 12:invokevirtual#22//Methodjava/io/PrintStream.println:(I)V 15:return
对于第二个例子,其实不难,结果是101,注意看一下流程,以后不能在犯这样的错误了。(流程为:首先比较temp=i,temp>100,,显然不成立,将i+=1,跳到syso那一句,打印的当然是101,再次循环同样有temp=i,temp>100,这次是成立的,然后i+=1,直接跳出循环,不会执行while里面的语句)。
第二个例子的汇编(只选取了main方法):
publicstaticvoidmain(java.lang.String[]); descriptor:([Ljava/lang/String;)V flags:ACC_PUBLIC,ACC_STATIC Code: stack=2,locals=2,args_size=1 0:bipush100//100压栈 2:istore_1//保存至第二个localvar(第一个localvar是方法参数) 3:iload_1//从第二个localvar加载 4:iinc1,1//给localvar的2号位置的int值增加1(局部变量自增,结果仍然在localvar中,操作数栈顶1不会变) 7:bipush100//100压栈 9:if_icmple15//比较操作数栈顶的两个int整型值,如果第一个小于或者等于第二个的话,然后跳转到15行 12:goto25//否则跳转到25行(即操作数栈顶1>操作数栈顶2) 15:getstatic#2//Fieldjava/lang/System.out:Ljava/io/PrintStream; 18:iload_1////从第一个个localvar加载 19:invokevirtual#3//Methodjava/io/PrintStream.println:(I)V//调用该方法 22:goto3//再次回跳至3,再次循环 25:return//退出
第三个例子:
packagetest; publicclassPlus_Test03{ staticintproPlus(){ inti=55; intj=++i; returnj;//56 } staticintpostPlus(){ inti=55; intj=i++; returnj;//55 } publicstaticvoidmain(String[]args){ System.out.println(proPlus());//56 System.out.println(postPlus());//55 } }
第三个例子的汇编:
staticintproPlus(); descriptor:()I flags:ACC_STATIC Code: stack=1,locals=2,args_size=0 0:bipush55//55压栈 2:istore_0//将int型栈顶的存储至第一个localvar 3:iinc0,1//第一个localvar加1 6:iload_0//从localvar加载 7:istore_1//保存至第二个localvar 8:iload_1//栈顶为第二个localvar 9:ireturnstaticintpostPlus(); descriptor:()I flags:ACC_STATIC Code: stack=1,locals=2,args_size=0 0:bipush55 2:istore_0 3:iload_0//加载至栈 4:iinc0,1//第一个localvar加1 7:istore_1 8:iload_1 9:ireturn
可见,前置++和后置++的不同点在于上面蓝色(//第一个localvar加1)的部分,这两部分是反过来的。对于前置来说,会将localvar中的数加1然后加载至栈中,而后置则是先从栈localvar中加载至栈,然后将localvar的加1,相当于留了一个备份。
结论:
一。前置、与后置++都是先将变量的值加1,而不是前置++先加1然后运算,而后置++先运算后加1。
二。从程序上说,后置++先将变量赋值给一个临时变量,然后将变量的值加1,接下来使用那个临时变量参与运算。
三。从指令上说,后置++在执行增值指令(iinc)前,先将变量的值压入栈,执行增值指令后,使用的是之前压入栈的值。
希望通过此文,彻底理解前置++和后置++的运算区别,谢谢大家对本站的支持!