国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

java finally塊執(zhí)行時機全面分析

2019-11-26 13:58:14
字體:
供稿:網(wǎng)友

java里 finally 關(guān)鍵字通常與try catch塊一起使用。用來在方法結(jié)束前或發(fā)生異常時做一些資源釋放的操作。最近也看到網(wǎng)上有一些討論try catch finally關(guān)鍵詞執(zhí)行的順序的文章,并給出了finally塊是在方法最后執(zhí)行的。

這些觀點普遍認為:

1) finally關(guān)鍵詞是在程序return語句后返回上一級方法前執(zhí)行的,其中返回值會保存在一個臨時區(qū)域,待執(zhí)行完finally塊的部分后,在將臨時區(qū)域的值返回。

2) 若finally塊里有返回值會替換掉程序中前面的try 或catch塊中return語句存放在臨時區(qū)域的值。

但是問題真的是這樣的嗎,我們仔細的想想,jvm是在運行時對字節(jié)碼指令進行解釋執(zhí)行的,當他在執(zhí)行到return語句后,他哪知道后面有沒有finally塊,如果沒有finally塊怎么辦,不管是字節(jié)碼指令還是計算機的指令應該是明確的,jvm沒有那么智能,同一個指令必須是明確的,不會包含兩層含義。所以對于return語句在運行時不管什么情況,統(tǒng)一會彈出棧的內(nèi)容并返回到調(diào)用方法。

與此同時,我們可以看到《深入java虛擬機》這一本書中給出了另外一種解釋。在java編譯器編譯finally子句時會生成jsr指令,它使jvm調(diào)轉(zhuǎn)到微型子例程進行執(zhí)行,也就是finally塊處,同時將程序中的return 0語句編譯為在調(diào)用jsr指令前棧中的返回變量到局部變量,調(diào)用jsr指令,執(zhí)行finally塊,finally塊返回,在將局部變量中的返回值壓入棧,執(zhí)行ireturn指令,從棧中彈出返回值,返回到調(diào)用方法,這里在執(zhí)行jsr指令前將返回值保存在局部變量中,是因為finally塊執(zhí)行的過程中可能發(fā)生異?;蛘哒f是也有返回值,只有這樣做才能保證最后程序執(zhí)行的一致性。由于《深入java虛擬機》寫的已經(jīng)也一些年代了,同時作者使用的jvm編譯器的實現(xiàn)及版本與本文討論的也有差別。所以經(jīng)過測試,對于同一程序不同的編譯器實現(xiàn)或版本不同的字節(jié)碼的生成稍微有些差別。有興趣可以看看這本書中finally子句生成的字節(jié)碼。

本文的字節(jié)碼生成使用的是Oracle的jdk8u-25版本的編譯器編譯生成的。

下面我們來看一個實例。

1.try catch finally 示例:

public class FinallyTest {  public static void main(String[] args) {    int r = test();    System.out.println(r);  }  public static int test()  {    try {      System.out.println("try");      //return 1/0;      return 0;    } catch (Exception e) {      System.out.println("exception");      return 100;    }finally{      System.out.println("finally");    }  }}

try塊中使用return 0語句,程序的運行結(jié)果是:

try
finally
0

try塊中使用 return 1/0 語句,程序運行的結(jié)果是:

exception
finally
100

其實通過運行結(jié)果我們可以看出的是finally塊是在try或catch塊中的return語句前其他語句后執(zhí)行的。也就是說程序的書寫順序與我們執(zhí)行順序不符,因為jvm是對字節(jié)碼進行解釋執(zhí)行的,那么我們需要看看java編譯器是如何編譯這段代碼的,看看其生成的字節(jié)碼究竟是什么樣的。

2.程序生成的部分字節(jié)碼:(java字節(jié)碼指令請參考)

public static int test();  descriptor: ()I  flags: ACC_PUBLIC, ACC_STATIC  Code:   stack=2, locals=2, args_size=0     0: getstatic   #20         // Field java/lang/System.out:Ljava/io/PrintStream;     3: ldc      #36         // String try     5: invokevirtual #38         // Method java/io/PrintStream.println:(Ljava/lang/String;)V     8: getstatic   #20         // Field java/lang/System.out:Ljava/io/PrintStream;    11: ldc      #41        // String finally    13: invokevirtual #38         // Method java/io/PrintStream.println:(Ljava/lang/String;)V    16: iconst_0    17: ireturn    18: astore_0    19: getstatic   #20         // Field java/lang/System.out:Ljava/io/PrintStream;    22: ldc      #43         // String exception    24: invokevirtual #38         // Method java/io/PrintStream.println:(Ljava/lang/String;)V    27: getstatic   #20         // Field java/lang/System.out:Ljava/io/PrintStream;    30: ldc      #41         // String finally    32: invokevirtual #38         // Method java/io/PrintStream.println:(Ljava/lang/String;)V    35: bipush    100    37: ireturn    38: astore_1    39: getstatic   #20         // Field java/lang/System.out:Ljava/io/PrintStream;    42: ldc      #41         // String finally    44: invokevirtual #38         // Method java/io/PrintStream.println:(Ljava/lang/String;)V    47: aload_1    48: athrow   Exception table:     from  to target type       0   8  18  Class java/lang/Exception       0   8  38  any      18  27  38  any

從紅色的部分我們可以看出:10,11行對應的是finally塊語句指令,16,17對應的是return 0指令,在try塊其他語句之后,return之前。而19,20對應的是finally塊指令,21,22對應的是return 100語句的指令,在catch其他語句之后,return之前,由此我們可以看出這些背后發(fā)生的一切是java編譯器為我們做了這一切,至于程序中發(fā)生的異常,jvm會從異常表找到對應處理異常的地址位置執(zhí)行。

因此我們可以得出結(jié)論finally塊中的語句會由java編譯器插入到try塊和catch塊return語句之前,其他語句之后。在這里也沒有生成jsr調(diào)用的子例程。所以才發(fā)生不管是執(zhí)行try塊還是執(zhí)行catch塊,最終在方法返回前都會執(zhí)行finally塊。

以上這篇java finally塊執(zhí)行時機全面分析就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持武林網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 武山县| 如皋市| 徐州市| 大城县| 泰宁县| 交城县| 湘潭市| 乌拉特中旗| 肇东市| 西吉县| 观塘区| 佛教| 尼勒克县| 赤峰市| 麻江县| 六枝特区| 剑河县| 临猗县| 乐亭县| 道孚县| 夏津县| 海门市| 綦江县| 大兴区| 都江堰市| 正定县| 卢湾区| 通许县| 阿坝县| 临桂县| 得荣县| 西华县| 牟定县| 泗洪县| 乌审旗| 宜都市| 贵州省| 迭部县| 桓仁| 景东| 健康|