日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java中return和finally到底哪個(gè)先執(zhí)行

本章節(jié)我們從字節(jié)碼的角度來探究下return和finally到底哪個(gè)先執(zhí)行。下面先來看一段簡單地源碼:

禪城網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),禪城網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為禪城近1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)公司要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的禪城做網(wǎng)站的公司定做!

 
 
 
  1. public class ReturnFinallyDemo { 
  2.     public static void main(String[] args) { 
  3.         System.out.println(case1()); 
  4.     } 
  5.  
  6.     public static int case1() { 
  7.         int x; 
  8.         try { 
  9.             x = 1; 
  10.             return x; 
  11.         } finally { 
  12.             x = 3; 
  13.         } 
  14.     } 
  15.  
  16. # 輸出 

上述代碼的輸出可以簡單地得出結(jié)論:return在finally之前執(zhí)行,我們來看下字節(jié)碼層面上發(fā)生了什么事情。下面截取case1方法的部分字節(jié)碼,并且對(duì)照源碼,將每個(gè)指令的含義注釋在后面:

 
 
 
  1. iconst_1 // 將常量1推入操作數(shù)棧頂  
  2. istore_0 // 彈出棧頂元素(1),保存到局部變量表slot[0],此時(shí)slot[0]=1。這兩條指令對(duì)應(yīng)源碼:x = 1;  
  3. iload_0 // 將局部變量表slot[0]的值推入操作數(shù)棧頂,也就是說把上面x的值推入棧頂  
  4. istore_1 // 彈出棧頂元素(1),保存到局部變量表slot[1],此時(shí)slot[1]=1。其實(shí),此時(shí)就已經(jīng)把要return的值準(zhǔn)備好了  
  5. iconst_3 // 將常量3推入操作數(shù)棧頂,這一條指令開始,其實(shí)是開始執(zhí)行finally中的代碼了  
  6. istore_0 // 彈出棧頂元素(3),保存到局部變量表slot[0],此時(shí)slot[0]=3。這兩個(gè)指令對(duì)應(yīng)源碼:x = 3;這里要注意的是,雖然都是更新了x的值,但是finally中的x和try中x的賦值,保存在了不同的局部變量表中 
  7. iload_1 // 將局部變量表slot[1]的值推入操作數(shù)棧頂,此時(shí)棧頂元素的值為1,是第3行指令保存的值 
  8.  
  9. ireturn // 將操作數(shù)棧頂?shù)闹捣祷亟o調(diào)用方 

從字節(jié)碼來看,似乎又是finally的代碼先執(zhí)行了,因?yàn)閕return指令確實(shí)是在最后執(zhí)行的,所以返回什么樣的值不在于誰先執(zhí)行,而在于ireturn指令返回的操作數(shù)棧頂?shù)脑厥呛螘r(shí)保存的。在上述代碼環(huán)境中,是try代碼塊中給x賦值的版本,也就是緊接著return語句后面的x所保存的版本。

下面再來看一個(gè)稍微復(fù)雜點(diǎn)的場(chǎng)景:

 
 
 
  1. public static int case2() { 
  2.     int x; 
  3.     try { 
  4.         x = 1; 
  5.         return ++x; 
  6.     } finally { 
  7.         x = 3; 
  8.     } 
  9.  
  10. # 輸出 

有了上面的分析,這個(gè)就很好理解了,我們還是來看下字節(jié)碼:

 
 
 
  1. iconst_1 // 將常量1推入操作數(shù)棧頂 
  2. istore_0 // 彈出棧頂元素(1),保存到局部變量表slot[0],此時(shí)slot[0]=1。這兩條指令對(duì)應(yīng)源碼:x = 1; 
  3. iinc          0, 1 // 對(duì)局部變量表slot[0]進(jìn)行自增(+1)操作,此時(shí)slot[0]=2,對(duì)應(yīng)源碼:++x;所以,可以看出return后面的表達(dá)式先執(zhí)行 
  4. iload_0 // 將局部變量表slot[0]的值推入操作數(shù)棧頂,也就是說把上面x的值(2)推入棧頂 
  5. istore_1 // 彈出棧頂元素(2),保存到局部變量表slot[1],此時(shí)slot[1]=2。其實(shí),此時(shí)就已經(jīng)把要return的值準(zhǔn)備好了 
  6. iconst_3 // 將常量3推入操作數(shù)棧頂,這一條指令開始,其實(shí)是開始執(zhí)行finally中的代碼了 
  7. istore_0 // 彈出棧頂元素(3),保存到局部變量表slot[0],此時(shí)slot[0]=3。這兩個(gè)指令對(duì)應(yīng)源碼:x = 3;這里要注意的是,雖然都是更新了x的值,但是finally中的x和try中x的賦值,保存在了不同的局部變量表中 
  8. iload_1 // 將局部變量表slot[1]的值推入操作數(shù)棧頂,此時(shí)棧頂元素的值為2,是第6行指令保存的值,也就是經(jīng)過++x之后的值 
  9. ireturn // 將操作數(shù)棧頂?shù)闹捣祷亟o調(diào)用方 

從上述代碼可以看出,return后面的指令先執(zhí)行,然后保存到局部變量表,接著執(zhí)行finally中的語句,最后執(zhí)行return指令本身。

總結(jié)一下,return指令是最后執(zhí)行的,如果return后面有表達(dá)式,則執(zhí)行完表達(dá)式之后就執(zhí)行finally中的語句,最后再執(zhí)行return指令。所以說finally和return到底哪個(gè)先執(zhí)行:return指令后面如果有表達(dá)式或方法調(diào)用的話,先執(zhí)行,然后執(zhí)行finally,最后執(zhí)行return指令。就像上面的程序演示的結(jié)果,不能光從x的賦值來看最終返回結(jié)果,從指令層面看,兩次對(duì)x的賦值,保存在局部變量表的位置不一樣。

最后,再來看一個(gè)平時(shí)不會(huì)這么去寫的場(chǎng)景:

 
 
 
  1. public static int case3() { 
  2.     int x; 
  3.     try { 
  4.         x = 1; 
  5.         return ++x; 
  6.     } finally { 
  7.         x = 3; 
  8.         return x; 
  9.     } 
  10. # 輸出 

這是一個(gè)finally返回結(jié)果的示例,平時(shí)不建議這么寫,我們同樣從字節(jié)碼的角度來分析下:

 
 
 
  1. iconst_1 // 將常量1推入操作數(shù)棧頂 
  2. istore_0 // 彈出棧頂元素(1),保存到局部變量表slot[0],此時(shí)slot[0]=1。這兩條指令對(duì)應(yīng)源碼:x = 1; 
  3. iinc          0, 1 // 對(duì)局部變量表slot[0]進(jìn)行自增(+1)操作,此時(shí)slot[0]=2,對(duì)應(yīng)源碼:++x;所以,可以看出return后面的表達(dá)式先執(zhí)行 
  4. iload_0  // 將局部變量表slot[0]的值推入操作數(shù)棧頂,也就是說把上面x的值(2)推入棧頂 
  5. istore_1 // 彈出棧頂元素(2),保存到局部變量表slot[1],此時(shí)slot[1]=2。 
  6. iconst_3 // 將常量3推入操作數(shù)棧頂,這一條指令開始,其實(shí)是開始執(zhí)行finally中的代碼了 
  7. istore_0 // 彈出棧頂元素(3),保存到變量表slot[0],此時(shí)slot[0]=3。這兩個(gè)指令對(duì)應(yīng)源碼:x = 3 
  8. iload_0  // 將局部變量表slot[0]的值(3)推入操作數(shù)棧,這是跟之前不一樣的地方,ireturn返回的值選擇的局部變量表不一樣 
  9. ireturn 

從字節(jié)碼以及解釋來看,直接忽略了try語句塊中的return指令,這樣的代碼會(huì)讓人產(chǎn)生疑惑,所以平時(shí)不建議這么寫。本章節(jié)就到這里了。


當(dāng)前題目:Java中return和finally到底哪個(gè)先執(zhí)行
本文網(wǎng)址:http://m.5511xx.com/article/dhpchgc.html