java中try catch語句和finally執行書序的原理

java方法是在棧幀中執行,棧幀是線程私有棧的單位,執行方法的線程會爲每一個方法分配一小塊棧空間來作爲該方法執行時的內存空間,棧幀分爲三個區域:

  1. 操作數棧,用來保存正在執行的表達式中的操作數,數據結構中學習過基於棧的多項式求值算法,操作數棧的作用和這個一樣
  2. 局部變量區,用來保存方法中使用的變量,包括方法參數,方法內部聲明的變量,以及方法中使用到的對象的成員變量或類的成員變量(靜態變量),最後兩種變量會複製到局部變量區,因此在多線程環境下,這種變量需要根據需要聲明爲volatile類型
  3. 字節碼指令區,這個不用解釋了,就是方法中的代碼翻譯成的指令

有了上面的預備知識我們就不難理解return和finally之間的關係了,我們要記住的就是在return [expression]這裏跟在return後面的表達式,返回的是return指令執行的時刻,操作數棧頂的值,不管expression是一個怎樣的表達式,究竟做了些什麼工作,對於return指令來說都不重要,他只負責把操作數棧頂的值返回。

而return expression是分成兩部分執行的:
執行:expression;
執行:return指令;

例如:return x+y;這句代碼先執行x+y,再執行return;首先執行將x以及y從局部變量區複製到操作數棧頂的指令,然後執行加法指令,這個時候結果x+y的值會保存在操作數棧的棧頂,最後執行return指令,返回操作數棧頂的值。

對於return x;先執行x,x也是一個表達式,這個表達式只有一個操作數,會執行將變量x從局部變量區複製到操作數棧頂的指令,然後執行return,返回操作數棧頂的值。因此return x實際返回的是return指令執行時,x在操作數棧頂的一個快照或者叫副本,而不是x這個值。

而當存在finally語句塊的時候,首先我們知道,finally語句是一定會執行,但他們的執行順序是怎麼樣的呢?他們的執行順序如下:
1、執行:expression,計算該表達式,結果保存在操作數棧頂;
2、執行:操作數棧頂值(expression的結果)複製到局部變量區作爲返回值;
3、執行:finally語句塊中的代碼;
4、執行:將第2步複製到局部變量區的返回值又複製回操作數棧頂;
5、執行:return指令,返回操作數棧頂的值;
我們可以看到,在第一步執行完畢後,整個方法的返回值就已經確定了,由於還要執行finally代碼塊,因此程序會將返回值暫存在局部變量區,騰出操作數棧用來執行finally語句塊中代碼,等finally執行完畢,再將暫存的返回值又複製回操作數棧頂。所以無論finally語句塊中執行了什麼操作,都無法影響返回值,所以試圖在finally語句塊中修改返回值是徒勞的。因此,finally語句塊設計出來的目的只是爲了讓方法執行一些重要的收尾工作,而不是用來計算返回值的。

所以在finally中更改返回值是無效的,因爲它只是更改了操作數棧頂端複製到局部變量區的快照,並不能真正的更改返回值,但是如果在

finally中使用return的話則是會將新的操作數棧的頂端數據返回,而不是之前複製到局部變量區用作返回內容快照的值返回,所以這樣是可以返回的,同樣的在cathch語句塊裏

也是這樣,只有重新出現了return纔有可能更改返回值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章