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