今天看一個Java SSH的面試題,題目大概意思是:try、catch中存在return語句,還會執行finally塊嗎?如果執行,是return先執行還是finally先執行?如果有多個return語句,結果如何?
看了以后我還真犯嘀咕,做了軟件開發這些年,還沒認真思考過則個問題,於是趕緊寫個測試測試代碼如下:
1 class Program 2 { 3 public static int a = 0; 4 static void Main(string[] args) 5 { 6 var result = GetValue(); 7 } 8 9 public static int GetValue() 10 { 11 try 12 { 13 a = 2; 14 throw new Exception(); 15 } 16 catch (Exception ex) 17 { 18 a = 3; 19 return a; 20 a = 4; 21 } 22 finally 23 { 24 a = 5; 25 } 26 } 27 }
為了探究個明白,使用ILSpy工具查看IL代碼, GetValue()的IL代碼如下:
1 .method public hidebysig static 2 int32 GetValue () cil managed 3 { 4 // Method begins at RVA 0x2064 5 // Code size 42 (0x2a) 6 .maxstack 1 7 .locals init ( 8 [0] class [mscorlib]System.Exception ex,//定義Exception類型變量 ex 9 [1] int32 CS$1$0000 //定義int32類型變量 CS$1$000 10 ) 11 12 IL_0000: nop //No Operation 沒有任何操作 13 .try 14 { 15 .try 16 { 17 IL_0001: nop 18 IL_0002: ldc.i4.2 //把int32 類型的數據2 推入計算堆棧上 19 IL_0003: stsfld int32 ConsoleApplication1.Program::a //用計算堆棧的值替換靜態字段a的值 20 IL_0008: newobj instance void [mscorlib]System.Exception::.ctor() //實例化Exception對象,並將對象推入到計算堆棧上 21 IL_000d: throw //引發當前位於計算堆棧上的異常對象 22 } // end .try 23 catch [mscorlib]System.Exception 24 { 25 IL_000e: stloc.0 //從計算堆棧的頂部彈出當前值(Exception對象)並將其存儲到索引 0 處的局部變量列表中 26 IL_000f: nop 27 IL_0010: ldc.i4.3 //把整數類型3推入計算堆棧上 28 IL_0011: stsfld int32 ConsoleApplication1.Program::a //用計算堆棧的值置換靜態變量a的值 29 IL_0016: ldsfld int32 ConsoleApplication1.Program::a //將靜態字段a的值推入計算堆棧上 30 IL_001b: stloc.1 //從計算堆棧的頂部彈出當前值,並將其存儲到索引 1 處的局部變量列表中 31 IL_001c: leave.s IL_0027 //退出受保護的代碼區域,無條件將控制轉移到目標指令 [ leave.s 指令清空計算堆棧並確保執行周圍適當的 finally 塊。] 32 } // end handler 33 } // end .try 34 finally 35 { 36 IL_001e: nop 37 IL_001f: ldc.i4.5 //把整數5推入計算堆棧上 38 IL_0020: stsfld int32 ConsoleApplication1.Program::a //用計算對象韓的值置換靜態變量a的值 39 IL_0025: nop 40 IL_0026: endfinally //將控制從異常塊的 fault 或 finally 子句轉移回公共語言結構 (CLI) 異常處理程序。 41 } // end handler 42 43 IL_0027: nop 44 IL_0028: ldloc.1 //將索引 1 處的局部變量加載到計算堆棧上 45 IL_0029: ret //從當前方法返回,並將返回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上 46 } // end of method Program::GetValue
通過IL代碼和相關的注釋,基本可以看出他們的執行流程,猜測出這個方法返回的結果以及靜態變量a最后的值是多少。
最后GetValue()方法返回的結果是3;靜態變量a的值是5;
但是 “IL_001c: leave.s IL_0027 ” leave.s 還沒看明白怎么回事?有相關熟悉的人,請指點,謝謝!
另外問題提到:有多個return的情況,返回哪個return的結果? 我試了一下,沒有發現允許執行多次return的可能!如果有請不吝指出!