亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java面試題之try中含return語句時代碼的執(zhí)行順序詳解

 更新時間:2017年04月28日 09:36:04   作者:LiuZh  
這篇文章主要介紹了關于java中的一道面試題,這套題就是在try中含return語句時代碼的執(zhí)行順序,這個問題看似簡單,卻暗藏殺機??!文中通過一個個例子詳細介紹了其中玄機,需要的朋友可以參考學習,下面來一起看看吧。

前言

最近在刷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()方法內(nèi),在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)了解該內(nèi)容可略過下面這一個小節(jié)點

java中的值傳遞

由于這只是本文內(nèi)容引申出去的知識點,不過多贅述,隨便嘮兩句,能借此明白則好,不明白希望借助搜索引擎明白一下!
在java的方法調(diào)用中,時常需要傳遞參數(shù),那么傳遞的參數(shù)是將之前的變量直接傳遞給方法內(nèi)了嗎?

顯然不是的,調(diào)用方法傳遞參數(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()方法內(nèi)拿到的a,只是t的一個副本(復制體)而并不直接是t,test()內(nèi)改變了a的值,并不影響t的值

以上是對于基本數(shù)據(jù)類型,如果對于對象呢?

如果參數(shù)是對象,那么傳遞的是對象的引用的副本(復制體),這也就是為什么在方法體內(nèi)對對象進行修改,會真正的改變對象。因為方法體外的引用和方法體內(nèi)的引用指向的是堆內(nèi)存中的同一個對象,傳遞的是對象的引用

如果這里還不能理解值傳遞,建議先理解一下這一個概念再繼續(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í)行!)并且這個保留,就是值傳遞性質(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是一個對象的引用,對象實例保存在堆內(nèi)存中,t的副本tt也是一個對象的引用,t和tt都指向堆內(nèi)存中的對象實例,那么不論修改誰,實際上對象實例都被修改了!

看完我這一通胡說八道,你應該了解了整個執(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í)行完畢。

好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • java實現(xiàn)酒店管理系統(tǒng)

    java實現(xiàn)酒店管理系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現(xiàn)酒店管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • Java泛型通配符的使用詳解

    Java泛型通配符的使用詳解

    本文主要介紹了Java泛型通配符的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • Java類加載異常:java.lang.ClassNotFoundException解決方法

    Java類加載異常:java.lang.ClassNotFoundException解決方法

    這篇文章主要給大家介紹了關于Java類加載異常:java.lang.ClassNotFoundException的解決方法,異常是Java編程語言中的一個標準異常類,它繼承自類,當在運行時嘗試加載類時,如果系統(tǒng)找不到指定的類文件就會拋出該異常,需要的朋友可以參考下
    2023-11-11
  • 簡單了解SPRINGIOC的底層原理演變過程

    簡單了解SPRINGIOC的底層原理演變過程

    這篇文章主要介紹了簡單了解SPRINGIOC的底層原理演變過程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • 基于Zookeeper實現(xiàn)服務注冊和服務發(fā)現(xiàn)功能

    基于Zookeeper實現(xiàn)服務注冊和服務發(fā)現(xiàn)功能

    無論是采用SOA還是微服務架構,都需要使用服務注冊和服務發(fā)現(xiàn)組件,本文將基于 Zookeeper 實現(xiàn)服務注冊和服務發(fā)現(xiàn)功能,如果跟我一樣有同樣的困惑,希望可以通過本文了解其他組件如何使用 Zookeeper 作為注冊中心的工作原理
    2023-09-09
  • spring mvc中@PathVariable / 帶斜杠方式獲取

    spring mvc中@PathVariable / 帶斜杠方式獲取

    這篇文章主要介紹了spring mvc中@PathVariable / 帶斜杠方式獲取,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java利用redis zset實現(xiàn)延時任務詳解

    Java利用redis zset實現(xiàn)延時任務詳解

    zset作為redis的有序集合數(shù)據(jù)結構存在,排序的依據(jù)就是score。本文就將利用zset score這個排序的這個特性,來實現(xiàn)延時任務,感興趣的可以了解一下
    2022-08-08
  • Java異常處理實例分析

    Java異常處理實例分析

    這篇文章主要介紹了Java異常處理,實例分析了java異常處理的常見用法,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • Spring?Boot3?跨域配置?Cors的方式

    Spring?Boot3?跨域配置?Cors的方式

    這篇文章主要介紹了Spring?Boot3?跨域配置?Cors,通過使用CORS,開發(fā)人員可以控制哪些外部網(wǎng)頁可以訪問他們的資源,從而提高應用程序的安全性,本文結合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2024-01-01
  • SpringBoot連接Redis2種模式解析

    SpringBoot連接Redis2種模式解析

    這篇文章主要介紹了SpringBoot連接Redis2種模式解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-05-05

最新評論