刷java面試題偶然看到這類問題(try/finally中含有return時的執(zhí)行順序)远剩,覺得挺有意思于是小小的研究了一下骇窍,希望經(jīng)過我添油加醋天馬行空之后,能給你帶來一定的幫助
原題
try {} 里有一個return語句痢掠,那么緊跟在這個try后的finally {}里的代碼會不會被執(zhí)行?什么時候被執(zhí)行?在return前還是后?
乍一看題目很簡單嘛嘲恍,java規(guī)范都說了,finally會在try代碼塊的return之前執(zhí)行姑廉,你這文章寫得沒意義涯保,不看了
你等等逃片!(拿起我身邊的五尺砍刀)
神奇栗子
看完這個栗子攻冷,你在想想執(zhí)行順序到底是怎樣的
栗子代碼
public static void main(String[] args) {
int result = test();
System.out.println(result);
}
public static int test() {
int t = 0;
try {
return t;
} finally {
++t;
}
}
分析一下
test()方法內等曼,在try中return了t凿蒜,那么在main方法中test()函數(shù)的返回值應該是t=0,即控制臺輸出0
但是因為有finally的存在州泊,而finally中對t進行了自增運算漂洋,并且finally會在try中的return語句之前執(zhí)行,所以正確的情況是控制臺輸出1
所以你最終確定的答案是:控制臺輸出1
然而事實并非如此演训,將程序跑起來之后样悟,得到的結果是:
輸出0
將栗子跑起來親眼看一下吧~
得到這個結果你也許要爆炸了庭猩,啥?java規(guī)范說的都是錯的礁苗?徙缴!
不用急,到我給sun洗地的時間了
洗地時間
在洗地之前疏叨,你很有必要先理解java中的值傳遞穿剖,如果你已經(jīng)了解該內容可略過下面這一個小節(jié)點
java中的值傳遞
由于這只是本文內容引申出去的知識點糊余,不過多贅述单寂,隨便嘮兩句吐辙,能借此明白則好昏苏,不明白希望借助搜索引擎明白一下!
在java的方法調用中贤惯,時常需要傳遞參數(shù)孵构,那么傳遞的參數(shù)是將之前的變量直接傳遞給方法內了嗎?
顯然不是的棒假,調用方法傳遞參數(shù)的時候精盅,傳遞的只是原變量的一個副本(復制體),換句話說就是妻枕,將變量的值傳遞給了方法體粘驰,而并沒有真正的將變量傳遞進去蝌数。
看個栗子:
public static void main(String[] args) {
int t = 0;
test(t);
System.out.println(t);
}
public static int test(int a) {
a = 111;
}
正確輸出是0,因為test()方法內拿到的a饵撑,只是t的一個副本(復制體)而并不直接是t唆貌,test()內改變了a的值,并不影響t的值
以上是對于基本數(shù)據(jù)類型语卤,如果對于對象呢粹舵?
如果參數(shù)是對象,那么傳遞的是對象的引用的副本(復制體)齐婴,這也就是為什么在方法體內對對象進行修改柠偶,會真正的改變對象睬关。因為方法體外的引用和方法體內的引用指向的是堆內存中的同一個對象,傳遞的是對象的引用
如果這里還不能理解值傳遞蔫仙,建議先理解一下這一個概念再繼續(xù)往下看
真的開始分析了
為了你看著方便丐箩,栗子代碼再來一份:(我真的不是為了湊字數(shù))
public static void main(String[] args) {
int result = test();
System.out.println(result);
}
public static int test() {
int t = 0;
try {
return t;
} finally {
++t;
}
}
- 當代碼執(zhí)行到
return t;
時屎勘,并不是直接將t返回了出去,而是將t保留了起來(因為還有一個finally語句塊沒有執(zhí)行!)
并且這個保留丑慎,就是值傳遞性質的一個保留竿裂,也就是保留的是t的一個副本(復制體)照弥,我這里先叫他tt吧(不是套套!这揣!)
- 接下來執(zhí)行finally語句塊曾沈,finally中將t做了自增運算,t的確變成了1姐帚,但是這并沒有影響t的復制體tt的值障涯!保留起來的tt值還是0!
- 這個時候執(zhí)行完了finally九秀,正式將保留起來的tt返回出去鼓蜒,于是,整個函數(shù)的返回結果就是0
- 這個t的副本(復制體)保留的地方是哪兒呢娇豫?我查了半天畅厢,有個應該靠譜的說法冯痢,保留在函數(shù)棧中,但具體保留的區(qū)域叫什么框杜,我也不知道浦楣,還請知情大佬指教一下!
上圖或許直觀一點咪辱?
叫我一聲靈魂畫師我可敢答應振劳!
那么如果,這個t是一個對象呢梧乘?按照前面說的值傳遞的問題澎迎,如果t是一個對象,在finally中對t進行修改选调,那么最終返回出去的t所顯示出來的數(shù)據(jù),應該是經(jīng)過修改的仁堪。
寫一個Person類來檢驗一下吧
public class Test {
public static void main(String[] args) {
Person result = test();
System.out.println(result.age);
}
public static Person test() {
Person t = new Person();
t.age = 0;
try {
return t;
} finally {
t.age++;
}
}
}
class Person {
int age;
}
這段代碼輸出的是1哮洽,因為Person是一個類,t是一個對象的引用弦聂,對象實例保存在堆內存中鸟辅,t的副本tt也是一個對象的引用,t和tt都指向堆內存中的對象實例莺葫,那么不論修改誰匪凉,實際上對象實例都被修改了!
看完我這一通胡說八道捺檬,你應該了解了整個執(zhí)行流程咯再层?
那么繼續(xù)開一個引申
又一個小栗子
如果在finally中也有一個return,會發(fā)生什么?
public static void main(String[] args) {
int result = test();
System.out.println(result);
}
public static int test() {
int t = 0;
try {
return t;
} finally {
++t;
return t;
}
}
最終輸出的結果是1
就是說聂受,如果try中有return而finally中也有return蒿秦,那么后者將會讓前者失效!
理解
=> try中將t保留了一份副本用于返回出去蛋济,到了finally中棍鳖,又有一個return語句,這時候又要創(chuàng)建一個用于返回的副本碗旅,那這個時候就有兩個副本了渡处,到底返回誰呢?取后者扛芽!
總結
這一個面試題骂蓖,看似簡單积瞒,卻暗藏殺機按狻!
可是說了這么多茫孔,結果就是finally在return之后執(zhí)行嗎叮喳?
非也,你沒看見return沒有真正的執(zhí)行完就開始執(zhí)行finally嗎缰贝?并且是先執(zhí)行完了finally馍悟,才執(zhí)行完return,這也就很好理解java規(guī)范中的finally在return之前執(zhí)行了剩晴。
不過锣咒,按如上情況,這句話應該變成這樣:finally比return先執(zhí)行完畢赞弥。是不是就更容易理解了呢毅整?
也就是說,return先被執(zhí)行了绽左,執(zhí)行return的時候發(fā)現(xiàn)有finally悼嫉,于是不能那么快執(zhí)行完畢return,先去執(zhí)行finally拼窥,等finally執(zhí)行完畢之后戏蔑,return才能執(zhí)行完畢。
全文下來鲁纠,真是用我的三寸不爛之舌經(jīng)過滔滔不絕的輸出連綿不絕的蠱惑打開了你的新世界大門啊
結語
更多內容歡迎訪問我的主頁或我的博客
如果我的文章確實有幫助到你总棵,請不要忘了點一下文末的"?"讓他變成"?"
作為一直雛雞難免很多地方理解不到位,文中若有錯誤請直(bu)接(yao)指(ma)出(wo)
寫作不易改含!