還是讓我們從一道面試題說(shuō)起吧,代碼如下,你知道方法執(zhí)行最后會(huì)輸出什么嗎?

public static void main(String[] args) {
int i = 0;
for (int j = 0; j < 50; j++) {
i = i++;
}
System.out.println(i);
}
不賣關(guān)子,最后輸出結(jié)果是0,而不是50,不知道跟你的認(rèn)知是否一致。
直接上字節(jié)碼,讓我們從字節(jié)碼層面看看i++背后的邏輯。
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: bipush 50
7: if_icmpge 21
10: iload_1
11: iinc 1, 1
14: istore_1
15: iinc 2, 1
18: goto 4
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return
先拋出這個(gè)方法局部變量表
0 1 2
args i j
pc 0~1兩個(gè)指令,為下標(biāo)為1的局部變量賦值為0,也就是局部變量i
pc 2~3兩個(gè)指令,為下表為2的局部變量賦值為0,也就是局部變量j
pc 4~7三個(gè)指令,取局部變量j的值與50比較,如果j>=50,跳轉(zhuǎn)到pc=21的指令處,如果不滿足則順序往下執(zhí)行
pc 10~14三個(gè)指令,是i=i++這行代碼編譯后的指令。在jvm中,局部變量表和操作數(shù)棧是兩個(gè)不同的存儲(chǔ)數(shù)據(jù)的內(nèi)存區(qū)域。iload_1表示將局部變量表中下標(biāo)為1的變量,也就是變量i的值復(fù)制一份,加載到操作數(shù)棧頂,innc 1,1 指令則將局部變量表中變量i的值加1再寫回局部變量表中變量i的位置,istore_1則將棧頂?shù)臄?shù)據(jù)覆蓋局部變量表中變量i的位置,所以執(zhí)行完這3個(gè)命令后,變量i的值并沒有發(fā)生變化。用偽代碼來(lái)表示這三個(gè)指令的邏輯就是這樣
int stack_top = local_variable[1];//把下標(biāo)為1的局部變量加載到棧頂
local_variable[1] = local_variable[1] + 1;//下標(biāo)為1的局部變量自增1
local_variable[1] = stack_top;//用棧頂?shù)闹蹈采w下標(biāo)為1的局部變量
pc 15指令iinc 2,1 將變量j自增1
pc 18指令goto 4,程序重新從pc=4的地方開始執(zhí)行
pc 21~25三個(gè)指令,就是打印下標(biāo)為1的局部變量,也就是打印變量i
所以,從pc10~14三個(gè)指令,可以看出變量i=i++這行代碼不會(huì)改變變量i的值,因此最后打印結(jié)果是0。
如果將 i=i++ 改成 i=++i,結(jié)果會(huì)是怎樣呢?
public static void main(String[] args) {
int i = 0;鄭州好的婦科醫(yī)院 http://www.zzkedayy.com/
for (int j = 0; j < 50; j++) {
i = ++i;
}
System.out.println(i);
}
輸出結(jié)果是50,還是直接看字節(jié)碼
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: iload_2
5: bipush 50
7: if_icmpge 21
10: iinc 1, 1
13: iload_1
14: istore_1
15: iinc 2, 1
18: goto 4
21: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iload_1
25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
28: return
除了指令10~14,對(duì)應(yīng)的代碼就是 i=++i,其他部分跟上面的字節(jié)碼指令一樣,所以我們只看不一樣的部分。
pc 10 innc 1,1 這里先執(zhí)行自增指令,將下標(biāo)為1的局部變量i的值自增1
pc 13 iload_1 將下標(biāo)為1的局部變量i的值加載到操作數(shù)棧頂
pc 14istore_1 將操作數(shù)棧頂?shù)闹蹈采w下標(biāo)為1的局部變量i的值
用偽代碼來(lái)表示這段邏輯就是這樣
local_variable[1] = local_variable[1] + 1;//下標(biāo)為1的局部變量自增1
int stack_top = local_variable[1];//把下標(biāo)為1的局部變量加載到棧頂
local_variable[1] = stack_top;//用棧頂?shù)闹蹈采w下標(biāo)為1的局部變量
所以,從pc10~14三個(gè)指令,可以看出變量 i=++i 這行代碼會(huì)使i的值增加1,因此最后打印結(jié)果是50。
與i++對(duì)應(yīng)的指令不同的地方是,++i會(huì)先執(zhí)行innc 1,1指令,這條指令會(huì)是i的值增加1,然后再參與計(jì)算。而i++會(huì)先將i的值保存到另外一個(gè)地方,然后再對(duì)i自增1,但是i=i++的賦值(也就是=)會(huì)用已保存的i的舊值覆蓋i的新值,所以i=i++,i的值并不會(huì)變。
總結(jié):講解了i=i++和i=++i的字節(jié)碼底層原理。
不知道朋友你理解了沒有,試試這道題輸出結(jié)果是什么
int i = 0;
int result = i++ + ++i + i++;
System.out.println(result);
創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國(guó)云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開啟,新人活動(dòng)云服務(wù)器買多久送多久。
當(dāng)前標(biāo)題:字節(jié)碼層面理解java中i++和++i的區(qū)別-創(chuàng)新互聯(lián)
本文地址:http://chinadenli.net/article38/edjsp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、網(wǎng)站設(shè)計(jì)公司、微信公眾號(hào)、面包屑導(dǎo)航、營(yíng)銷型網(wǎng)站建設(shè)、全網(wǎng)營(yíng)銷推廣
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容