生活随笔
收集整理的這篇文章主要介紹了
从JVM指令层面看try-catch-finally返回值问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
貌似很多人對下面的方法的返回值都比較迷糊:
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 查看字節碼:
重點查看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();?????--構造方法就不分析了????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個參數(this)?????0:???iconst_1????????--將int值?1?壓棧?????1:???istore_1????????--將棧頂值(即1)彈出保存至局部變量表第2個位置(局部變量表下標是從0開始的,但是0位置被this變量占用了)?????2:???iload_1?????????--將局部變量表第2個位置的值壓棧?????3:???istore??4???????--將棧頂的值彈出并保存至局部變量表第5個位置(這里可以看到)?????5:???iconst_3????????--(這里開始為finally塊)將int值3壓棧?????6:???istore_1????????--將棧頂的值(即3)彈出并存儲至局部變量表第2個位置?????7:???iload???4???????--將局部變量表第5個位置(即1)壓棧?????9:???ireturn?????????--返回棧頂的值(即1),?結束方法調用(該路徑為try(未拋異常)?->?finally)??????????10:??astore_2????????--將棧頂的引用(這里即為catch塊中捕捉到的異常e)存儲至局部變量表的第3個位置?????11:??iconst_2????????--將int值2壓棧?????12:??istore_1????????--將棧頂值(即2)彈出并存儲至局部變量表第2個位置?????13:??iload_1?????????--將局部變量表第2個位置的值(即2)壓棧?????14:??istore??4???????--將棧頂值彈出(即2)并保存至局部變量表第5個位置,原來第五個位置是1,現在1被覆蓋了,變為2?????16:??iconst_3????????--(這里開始為finally塊)將int值3壓棧?????17:??istore_1????????--將棧頂的值(即3)彈出并存儲至局部變量表第2個位置?????18:??iload???4???????--將局部變量表第5個位置(即2)壓棧?????20:??ireturn?????????--返回棧頂的值(即2),結束方法調用(該路徑為try(拋Exception或其子類異常)?->?catch?->?finally)??????????21:??astore_3????????--將棧頂的引用(這里為非Exception的子類異常)存儲至局部變量表的第4個位置?????22:??iconst_3????????--將int值3壓棧?????23:??istore_1????????--將棧頂值(即3)彈出并存儲至局部變量表第二個位置?????24:??aload_3?????????--將局部變量表第4個位置(即為異常引用)壓棧?????25:??athrow??????????--將棧頂的異常拋出(該路徑為try(拋非Exception或其子類異常)?->?finally,?或者try(拋Exception或其子類異常)?->?catch(拋任何異常)?->?finally?)????Exception?table:?????from???to??target?type???????0?????5????10???Class?java/lang/Exception??--若執行到0-5行(即在try塊中)拋出java.lang.Exception或其子類則跳轉至第10行執行(即catch塊)???????0?????5????21???any????????????????????????--若執行到0-5行(即在try塊中)拋出非java.lang.Exception或其子類則跳轉至第21行執行(即finally塊)??????10????16????21???any????????????????????????--若執行到10-16行(即在catch塊中)拋出任何異常則跳轉至21行執行(即finally塊)????LineNumberTable:??????--這個表為源碼行數與字節碼行數的映射?????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:???????--這個即為局部變量表,?start和length結合起來就可以確定該變量的作用范圍,?例如this作用范圍為整個方法?????Start??Length??Slot??Name???Signature?????0??????26??????0????this???????Lcc/lixiaohui/demo/ReturnValueTest;???--占用第1個slot(一個slot應該是32bits)?????2??????8??????1????a???????I?????????????????????????????????????????--I標識int,?占用第2個slot?????13??????8??????1????a???????I????????????????????????????????????????--占用第2個slot?????24??????2??????1????a???????I????????????????????????????????????????--占用第2個slot?????11??????10??????2????e???????Ljava/lang/Exception;???????????????????--占用第3個slot??????}???
可以發現jvm始終把返回值放在最后一個局部變量表的位置,而且在finally中改變x并不影響返回值.
轉載于:https://my.oschina.net/u/2978057/blog/769725
總結
以上是生活随笔為你收集整理的从JVM指令层面看try-catch-finally返回值问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。