激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|C/C++|

服務器之家 - 編程語言 - JAVA教程 - Java中return和finally到底哪個先執行

Java中return和finally到底哪個先執行

2020-10-28 21:42今日頭條Java成長催化師 JAVA教程

本章節我們從字節碼的角度來探究下return和finally到底哪個先執行。下面先來看一段簡單地源碼。

Java中return和finally到底哪個先執行

本章節我們從字節碼的角度來探究下returnfinally到底哪個先執行。下面先來看一段簡單地源碼:

public class ReturnFinallyDemo { 

    public static void main(String[] args) { 

        System.out.println(case1()); 

    } 

 

    public static int case1() { 

        int x; 

        try { 

            x = 1; 

            return x; 

        } finally { 

            x = 3; 

        } 

    } 

 

# 輸出 

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

iconst_1 // 將常量1推入操作數棧頂  

istore_0 // 彈出棧頂元素(1),保存到局部變量表slot[0],此時slot[0]=1。這兩條指令對應源碼:x = 1;  

iload_0 // 將局部變量表slot[0]的值推入操作數棧頂,也就是說把上面x的值推入棧頂  

istore_1 // 彈出棧頂元素(1),保存到局部變量表slot[1],此時slot[1]=1。其實,此時就已經把要return的值準備好了  

iconst_3 // 將常量3推入操作數棧頂,這一條指令開始,其實是開始執行finally中的代碼了  

istore_0 // 彈出棧頂元素(3),保存到局部變量表slot[0],此時slot[0]=3。這兩個指令對應源碼:x = 3;這里要注意的是,雖然都是更新了x的值,但是finally中的x和try中x的賦值,保存在了不同的局部變量表中 

iload_1 // 將局部變量表slot[1]的值推入操作數棧頂,此時棧頂元素的值為1,是第3行指令保存的值 

 

ireturn // 將操作數棧頂的值返回給調用方 

從字節碼來看,似乎又是finally的代碼先執行了,因為ireturn指令確實是在最后執行的,所以返回什么樣的值不在于誰先執行,而在于ireturn指令返回的操作數棧頂的元素是何時保存的。在上述代碼環境中,是try代碼塊中給x賦值的版本,也就是緊接著return語句后面的x所保存的版本。

下面再來看一個稍微復雜點的場景:

public static int case2() { 

    int x; 

    try { 

        x = 1; 

        return ++x; 

    } finally { 

        x = 3; 

    } 

 

# 輸出 

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

iconst_1 // 將常量1推入操作數棧頂 

istore_0 // 彈出棧頂元素(1),保存到局部變量表slot[0],此時slot[0]=1。這兩條指令對應源碼:x = 1; 

iinc          0, 1 // 對局部變量表slot[0]進行自增(+1)操作,此時slot[0]=2,對應源碼:++x;所以,可以看出return后面的表達式先執行 

iload_0 // 將局部變量表slot[0]的值推入操作數棧頂,也就是說把上面x的值(2)推入棧頂 

istore_1 // 彈出棧頂元素(2),保存到局部變量表slot[1],此時slot[1]=2。其實,此時就已經把要return的值準備好了 

iconst_3 // 將常量3推入操作數棧頂,這一條指令開始,其實是開始執行finally中的代碼了 

istore_0 // 彈出棧頂元素(3),保存到局部變量表slot[0],此時slot[0]=3。這兩個指令對應源碼:x = 3;這里要注意的是,雖然都是更新了x的值,但是finally中的x和try中x的賦值,保存在了不同的局部變量表中 

iload_1 // 將局部變量表slot[1]的值推入操作數棧頂,此時棧頂元素的值為2,是第6行指令保存的值,也就是經過++x之后的值 

ireturn // 將操作數棧頂的值返回給調用方 

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

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

最后,再來看一個平時不會這么去寫的場景:

public static int case3() { 

    int x; 

    try { 

        x = 1; 

        return ++x; 

    } finally { 

        x = 3; 

        return x; 

    } 

# 輸出 

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

iconst_1 // 將常量1推入操作數棧頂 

istore_0 // 彈出棧頂元素(1),保存到局部變量表slot[0],此時slot[0]=1。這兩條指令對應源碼:x = 1; 

iinc          0, 1 // 對局部變量表slot[0]進行自增(+1)操作,此時slot[0]=2,對應源碼:++x;所以,可以看出return后面的表達式先執行 

iload_0  // 將局部變量表slot[0]的值推入操作數棧頂,也就是說把上面x的值(2)推入棧頂 

istore_1 // 彈出棧頂元素(2),保存到局部變量表slot[1],此時slot[1]=2。 

iconst_3 // 將常量3推入操作數棧頂,這一條指令開始,其實是開始執行finally中的代碼了 

istore_0 // 彈出棧頂元素(3),保存到變量表slot[0],此時slot[0]=3。這兩個指令對應源碼:x = 3 

iload_0  // 將局部變量表slot[0]的值(3)推入操作數棧,這是跟之前不一樣的地方,ireturn返回的值選擇的局部變量表不一樣 

ireturn 

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 性少妇videosexfreexx | 日本羞羞的午夜电视剧 | 国内久久久久 | 亚洲国产精品久久久久久久久久久 | 羞羞视频免费网站男男 | 色悠悠久久久久 | 成人福利免费在线观看 | 欧美中文字幕一区二区三区亚洲 | 九色新网址 | 特级黄一级播放 | 久久人人97超碰国产公开结果 | 日韩.www | 欧美日韩亚洲一区二区三区 | 噜噜社| 欧美亚洲一区二区三区四区 | 久久精国| 亚洲日韩精品欧美一区二区 | 日本免费成人网 | 午夜精品成人 | 国产精品视频一区二区三区四区国 | 男女污视频在线观看 | 水卜樱一区二区av | 古装三级在线观看 | 韩国精品视频在线观看 | 久久久国产电影 | 亚洲人成在线播放网站 | 国产精品久久久久久久久久尿 | 国产深夜福利视频在线播放 | 欧美特一级片 | 又黄又爽免费无遮挡在线观看 | 久久一区二区三区av | 操毛片 | 国产在线欧美 | 一级做a在线观看 | 天天干天天碰 | 国产精品jk白丝蜜臀av软件 | 国产女厕一区二区三区在线视 | 国产精品久久久久一区二区 | 中文字幕免费一区 | 日韩精品中文字幕一区二区 | 日韩av在线网址 |