java finally塊履行機會周全剖析。本站提示廣大學習愛好者:(java finally塊履行機會周全剖析)文章只能為提供參考,不一定能成為您想要的結果。以下是java finally塊履行機會周全剖析正文
java裡 finally 症結字平日與try catch塊一路應用。用來在辦法停止前或產生異常時做一些資本釋放的操作。比來也看到網上有一些評論辯論try catch finally症結詞履行的次序的文章,並給出了finally塊是在辦法最初履行的。
這些不雅點廣泛以為:
1) finally症結詞是在法式return語句後前往上一級辦法前履行的,個中前往值會保留在一個暫時區域,待履行完finally塊的部門後,在將暫時區域的值前往。
2) 若finally塊裡有前往值會調換失落法式中後面的try 或catch塊中return語句寄存在暫時區域的值。
然則成績真的是如許的嗎,我們細心的想一想,jvm是在運轉時對字節碼指令停止說明履行的,當他在履行到return語句後,他哪曉得前面有無finally塊,假如沒有finally塊怎樣辦,不論是字節碼指令照樣盤算機的指令應當是明白的,jvm沒有那末智能,統一個指令必需是明白的,不會包括兩層寄義。所以關於return語句在運轉時不論甚麼情形,同一會彈出棧的內容並前往到挪用辦法。
與此同時,我們可以看到《深刻java虛擬機》這一本書中給出了別的一種說明。在java編譯器編譯finally子句時會生成jsr指令,它使jvm調轉到微型子例程停止履行,也就是finally塊處,同時將法式中的return 0語句編譯為在挪用jsr指令前棧中的前往變量到部分變量,挪用jsr指令,履行finally塊,finally塊前往,在將部分變量中的前往值壓入棧,履行ireturn指令,從棧中彈出前往值,前往到挪用辦法,這裡在履行jsr指令前將前往值保留在部分變量中,是由於finally塊履行的進程中能夠產生異常或許說是也有前往值,只要如許做能力包管最初法式履行的分歧性。因為《深刻java虛擬機》寫的曾經也一些年月了,同時作者應用的jvm編譯器的完成及版本與本文評論辯論的也有差異。所以經由測試,關於統一法式分歧的編譯器完成或版本分歧的字節碼的生成略微有些差異。有興致可以看看這本書中finally子句生成的字節碼。
本文的字節碼生成應用的是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語句,法式的運轉成果是:
try
finally
0
try塊中應用 return 1/0 語句,法式運轉的成果是:
exception
finally
100
其實經由過程運轉成果我們可以看出的是finally塊是在try或catch塊中的return語句前其他語句後履行的。也就是說法式的書寫次序與我們履行次序不符,由於jvm是對字節碼停止說明履行的,那末我們須要看看java編譯器是若何編譯這段代碼的,看看其生成的字節碼畢竟是甚麼樣的。
2.法式生成的部門字節碼:(java字節碼指令請參考)
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之前,由此我們可以看出這些面前產生的一切是java編譯器為我們做了這一切,至於法式中產生的異常,jvm會從異常表找到對應處置異常的地址地位履行。
是以我們可以得出結論finally塊中的語句會由java編譯器拔出到try塊和catch塊return語句之前,其他語句以後。在這裡也沒有生成jsr挪用的子例程。所以才產生不論是履行try塊照樣履行catch塊,終究在辦法前往前都邑履行finally塊。
以上這篇java finally塊履行機會周全剖析就是小編分享給年夜家的全體內容了,願望能給年夜家一個參考,也願望年夜家多多支撐。