Java 中 finally 与 return 的执行顺序详解
java方法是在棧幀中執(zhí)行,棧幀是線程私有棧的單位,執(zhí)行方法的線程會為每一個方法分配一小塊棧空間來作為該方法執(zhí)行時的內(nèi)存空間,棧幀分為三個區(qū)域:
1 . 操作數(shù)棧,用來保存正在執(zhí)行的表達式中的操作數(shù),數(shù)據(jù)結(jié)構(gòu)中學(xué)習(xí)過基于棧的多項式求值算法,操作數(shù)棧的作用和這個一樣
2 . 局部變量區(qū),用來保存方法中使用的變量,包括方法參數(shù),方法內(nèi)部聲明的變量,以及方法中使用到的對象的成員變量或類的成員變量(靜態(tài)變量),最后兩種變量會復(fù)制到局部變量區(qū),因此在多線程環(huán)境下,這種變量需要根據(jù)需要聲明為volatile類型
3 . 字節(jié)碼指令區(qū),這個不用解釋了,就是方法中的代碼翻譯成的指令
return語句
在沒有finally語句塊的情況下return語句的執(zhí)行方式。現(xiàn)在我們先看看return語句,return語句的格式如下:
return [expression];其中expression(表達式)是可選的,因為有些方法沒有返回值,所以return后面也就沒有表達式,或者可以看做是空的表達式。
??我們知道return語句的作用可以結(jié)束方法并返回一個值,那么他返回的是哪里的值呢?返回的是return指令執(zhí)行的時刻,操作數(shù)棧頂?shù)闹?#xff0c;不管expression是一個怎樣的表達式,究竟做了些什么工作,對于return指令來說都不重要,他只負責把操作數(shù)棧頂?shù)闹捣祷亍6鴕eturn expression是分成兩部分執(zhí)行的:
例如:return x+y;這句代碼先執(zhí)行x+y,再執(zhí)行return;首先執(zhí)行將x 以及y 從局部變量區(qū)復(fù)制到操作數(shù)棧頂?shù)闹噶?#xff0c;然后執(zhí)行加法指令,這個時候結(jié)果 x+y 的值會保存在操作數(shù)棧的棧頂,最后執(zhí)行return指令,返回操作數(shù)棧頂?shù)闹怠?br /> ??
對于return x;先執(zhí)行x,x也是一個表達式,這個表達式只有一個操作數(shù),會執(zhí)行將變量x從局部變量區(qū)復(fù)制到操作數(shù)棧頂?shù)闹噶?#xff0c;然后執(zhí)行return,返回操作數(shù)棧頂?shù)闹怠R虼藃eturn x;實際返回的是return指令執(zhí)行時,x在操作數(shù)棧頂?shù)囊粋€快照或者叫副本,而不是x這個值。
finally 語句塊:
如果方法中有finally語句塊,那么return語句又是如何執(zhí)行的呢?例如下面這段代碼:
try {return expression; } finally {do some work; }首先我們知道,finally語句是一定會執(zhí)行的,但他們的執(zhí)行順序是怎么樣的呢?他們的執(zhí)行順序如下:
??
1 . 執(zhí)行:expression,計算該表達式,結(jié)果保存在操作數(shù)棧頂;
2 . 執(zhí)行:操作數(shù)棧頂值(expression的結(jié)果)復(fù)制到局部變量區(qū)作為返回值;
3 . 執(zhí)行:finally語句塊中的代碼;
4 . 執(zhí)行:將第2步復(fù)制到局部變量區(qū)的返回值又復(fù)制回操作數(shù)棧頂;
5 . 執(zhí)行:return指令,返回操作數(shù)棧頂?shù)闹?#xff1b;
我們可以看到,在第一步執(zhí)行完畢后,整個方法的返回值就已經(jīng)確定了,由于還要執(zhí)行finally代碼塊,因此程序會將返回值暫存在局部變量區(qū),騰出操作數(shù)棧用來執(zhí)行finally語句塊中代碼,等finally執(zhí)行完畢,再將暫存的返回值又復(fù)制回操作數(shù)棧頂。所以無論finally語句塊中執(zhí)行了什么操作,都無法影響返回值,所以試圖在finally語句塊中修改返回值是徒勞的。因此,finally語句塊設(shè)計出來的目的只是為了讓方法執(zhí)行一些重要的收尾工作,而不是用來計算返回值的。
示例代碼:
public class FinallyDemo {public int testMethod(String _int,String _className){int x = 1;try{Integer.valueOf(_int);Class.forName(_className);//如果上面兩句代碼沒有發(fā)生異常,對于return x這句代碼,程序會先計算表達式x//即將x從局部變量區(qū)復(fù)制到操作數(shù)棧頂,結(jié)果就是操作數(shù)棧頂?shù)闹?#xff0c;也就是x的值,為1//然后將操作數(shù)棧頂?shù)闹祻?fù)制到局部變量區(qū)(假設(shè)這個復(fù)制到局部變量區(qū)的值叫returnvalue),再執(zhí)行finally代碼塊,在finally代碼塊//中,x的值被修改為3(即局部變量區(qū)中的x值),finally執(zhí)行完,程序又將returnvalue復(fù)制到操作數(shù)棧頂,然后執(zhí)行return指令,返回//操作數(shù)棧頂?shù)闹?#xff0c;最終返回值是1return x;}catch(ClassNotFoundException e){//同樣發(fā)生了ClassNotFoundException,x的值被修改成2//因此在catch中的return x語句中定義了返回值大小為2,所以最終返回的是2x = 2;return x;}finally{//這句代碼一定會執(zhí)行的,這里的代碼執(zhí)行結(jié)束后才會結(jié)束方法并返回值,因此在finally語句修改x不會影響返回值,因為返回值在return 后面的//表達式執(zhí)行完就已經(jīng)確定了,他是x的快照,而不是xx = 3;}}public static void main(String [] args){try{FinallyDemo demo = new FinallyDemo();int i_1 = demo.testMethod("123123", "expert.in.java.lang.CalendarDemo");System.out.println(i_1);//結(jié)果為1int i_2 = demo.testMethod("123123", "com.edu.cn.qj.MyClass");System.out.println(i_2);//結(jié)果為2int i_3 = demo.testMethod("dsadf", "expert.in.java.lang.CalendarDemo");System.out.println(i_3);//沒有返回值,會拋出異常}finally{}} }總結(jié)
以上是生活随笔為你收集整理的Java 中 finally 与 return 的执行顺序详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java方法的可变参数
- 下一篇: java美元兑换,(Java实现) 美元