生活随笔
收集整理的這篇文章主要介紹了
从JVM指令层面看try-catch-finally返回值问题
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
貌似很多人對下面的方法的返回值都比較迷糊:
Java代碼
package?cc.lixiaohui.demo;????????public?class?ReturnValueTest?{????????public?int?test()?{????????????int?a;????????????try?{????????????????a?=?1;????????????????//int?b?=?1?/?0;????????????????return?a;????????????}?catch?(Exception?e)?{????????????????a?=?2;????????????????return?a;????????????}?finally?{????????????????a?=?3;????????????}????????}????}???
test方法的返回值自然是1,如果把注釋那行去掉,那就是2.
?
為什么?
用javap -verbose ReturnValueTest 查看字節(jié)碼:
重點(diǎn)查看test()方法指令: 下載
Javap代碼
Compiled?from?"ReturnValueTest.java"??public?class?cc.lixiaohui.demo.ReturnValueTest?extends?java.lang.Object????SourceFile:?"ReturnValueTest.java"????minor?version:?0????major?version:?49?????????Constant?pool:????????--常量池??const?#1?=?class????????#2;?????//??cc/lixiaohui/demo/ReturnValueTest??const?#2?=?Asciz????????cc/lixiaohui/demo/ReturnValueTest;??const?#3?=?class????????#4;?????//??java/lang/Object??const?#4?=?Asciz????????java/lang/Object;??const?#5?=?Asciz????????<init>;??const?#6?=?Asciz????????()V;??const?#7?=?Asciz????????Code;??const?#8?=?Method???????#3.#9;??//??java/lang/Object."<init>":()V??const?#9?=?NameAndType??#5:#6;//??"<init>":()V??const?#10?=?Asciz???????LineNumberTable;??const?#11?=?Asciz???????LocalVariableTable;??const?#12?=?Asciz???????this;??const?#13?=?Asciz???????Lcc/lixiaohui/demo/ReturnValueTest;;??const?#14?=?Asciz???????test;??const?#15?=?Asciz???????()I;??const?#16?=?class???????#17;????//??java/lang/Exception??const?#17?=?Asciz???????java/lang/Exception;??const?#18?=?Asciz???????a;??const?#19?=?Asciz???????I;??const?#20?=?Asciz???????e;??const?#21?=?Asciz???????Ljava/lang/Exception;;??const?#22?=?Asciz???????SourceFile;??const?#23?=?Asciz???????ReturnValueTest.java;????{??public?cc.lixiaohui.demo.ReturnValueTest();?????--構(gòu)造方法就不分析了????Code:?????Stack=1,?Locals=1,?Args_size=1?????0:???aload_0?????1:???invokespecial???#8;?//Method?java/lang/Object."<init>":()V?????4:???return????LineNumberTable:?????line?8:?0??????LocalVariableTable:?????Start??Length??Slot??Name???Signature?????0??????5??????0????this???????Lcc/lixiaohui/demo/ReturnValueTest;??????public?int?test();????Code:?????Stack=1,?Locals=5,?Args_size=1?--?[Stack=1貌似表示棧深度為1(不確定),]Locals=5表示局部變量表長度為5,?Args_size=1表示該方法有1個(gè)參數(shù)(this)?????0:???iconst_1????????--將int值?1?壓棧?????1:???istore_1????????--將棧頂值(即1)彈出保存至局部變量表第2個(gè)位置(局部變量表下標(biāo)是從0開始的,但是0位置被this變量占用了)?????2:???iload_1?????????--將局部變量表第2個(gè)位置的值壓棧?????3:???istore??4???????--將棧頂?shù)闹祻棾霾⒈4嬷辆植孔兞勘淼?/span>5個(gè)位置(這里可以看到)?????5:???iconst_3????????--(這里開始為finally塊)將int值3壓棧?????6:???istore_1????????--將棧頂?shù)闹?#xff08;即3)彈出并存儲(chǔ)至局部變量表第2個(gè)位置?????7:???iload???4???????--將局部變量表第5個(gè)位置(即1)壓棧?????9:???ireturn?????????--返回棧頂?shù)闹?#xff08;即1),?結(jié)束方法調(diào)用(該路徑為try(未拋異常)?->?finally)??????????10:??astore_2????????--將棧頂?shù)囊?#xff08;這里即為catch塊中捕捉到的異常e)存儲(chǔ)至局部變量表的第3個(gè)位置?????11:??iconst_2????????--將int值2壓棧?????12:??istore_1????????--將棧頂值(即2)彈出并存儲(chǔ)至局部變量表第2個(gè)位置?????13:??iload_1?????????--將局部變量表第2個(gè)位置的值(即2)壓棧?????14:??istore??4???????--將棧頂值彈出(即2)并保存至局部變量表第5個(gè)位置,原來第五個(gè)位置是1,現(xiàn)在1被覆蓋了,變?yōu)?/span>2?????16:??iconst_3????????--(這里開始為finally塊)將int值3壓棧?????17:??istore_1????????--將棧頂?shù)闹?#xff08;即3)彈出并存儲(chǔ)至局部變量表第2個(gè)位置?????18:??iload???4???????--將局部變量表第5個(gè)位置(即2)壓棧?????20:??ireturn?????????--返回棧頂?shù)闹?#xff08;即2),結(jié)束方法調(diào)用(該路徑為try(拋Exception或其子類異常)?->?catch?->?finally)??????????21:??astore_3????????--將棧頂?shù)囊?#xff08;這里為非Exception的子類異常)存儲(chǔ)至局部變量表的第4個(gè)位置?????22:??iconst_3????????--將int值3壓棧?????23:??istore_1????????--將棧頂值(即3)彈出并存儲(chǔ)至局部變量表第二個(gè)位置?????24:??aload_3?????????--將局部變量表第4個(gè)位置(即為異常引用)壓棧?????25:??athrow??????????--將棧頂?shù)漠惓伋?該路徑為try(拋非Exception或其子類異常)?->?finally,?或者try(拋Exception或其子類異常)?->?catch(拋任何異常)?->?finally?)????Exception?table:?????from???to??target?type???????0?????5????10???Class?java/lang/Exception??--若執(zhí)行到0-5行(即在try塊中)拋出java.lang.Exception或其子類則跳轉(zhuǎn)至第10行執(zhí)行(即catch塊)???????0?????5????21???any????????????????????????--若執(zhí)行到0-5行(即在try塊中)拋出非java.lang.Exception或其子類則跳轉(zhuǎn)至第21行執(zhí)行(即finally塊)??????10????16????21???any????????????????????????--若執(zhí)行到10-16行(即在catch塊中)拋出任何異常則跳轉(zhuǎn)至21行執(zhí)行(即finally塊)????LineNumberTable:??????--這個(gè)表為源碼行數(shù)與字節(jié)碼行數(shù)的映射?????line?13:?0?????line?14:?2?????line?19:?5?????line?14:?7?????line?15:?10?????line?16:?11?????line?17:?13?????line?19:?16?????line?17:?18?????line?18:?21?????line?19:?22?????line?20:?24??????LocalVariableTable:???????--這個(gè)即為局部變量表,?start和length結(jié)合起來就可以確定該變量的作用范圍,?例如this作用范圍為整個(gè)方法?????Start??Length??Slot??Name???Signature?????0??????26??????0????this???????Lcc/lixiaohui/demo/ReturnValueTest;???--占用第1個(gè)slot(一個(gè)slot應(yīng)該是32bits)?????2??????8??????1????a???????I?????????????????????????????????????????--I標(biāo)識(shí)int,?占用第2個(gè)slot?????13??????8??????1????a???????I????????????????????????????????????????--占用第2個(gè)slot?????24??????2??????1????a???????I????????????????????????????????????????--占用第2個(gè)slot?????11??????10??????2????e???????Ljava/lang/Exception;???????????????????--占用第3個(gè)slot??????}???
可以發(fā)現(xiàn)jvm始終把返回值放在最后一個(gè)局部變量表的位置,而且在finally中改變x并不影響返回值.
轉(zhuǎn)載于:https://my.oschina.net/u/2978057/blog/769725
總結(jié)
以上是生活随笔為你收集整理的从JVM指令层面看try-catch-finally返回值问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。