經過字節碼分析Java異常處理機制

在上一次【http://www.javashuo.com/article/p-xthqgezz-dy.html】初步對異常表相關的概念進行了瞭解,先來回顧一下:
html

其源代碼也貼一下:java

下面來看一下jclasslib關於這個test()的信息:web

我們重點來看一下Code信息,以下:debug

其實也就是對應於javap -verbose看到的字節碼信息,我們一行行的跟源代碼進行比對一下:server

點擊看一下new的助字符的官方解釋:htm

實際對應源碼就是:對象

查看一下官網的解釋:blog

查看一下解釋:ip

回到我們這句話其意思就是將常量「test.txt」推到常量池中使得能構造出FileInputStream對象。ssl

這個咱們以前瞭解過,這裏再看一下官網的解釋:

回到我們這句話意思就是調用了父類的構造方法,由於建立子類其父類確定得要先被建立才行。

也就是將"is"存到局部變量當中,因此前面的這些助記符就對應這樣一個句源碼,以下:

對應於

相似的下面這一行源代碼其實對應的助字符差很少,以下:

下面也來瞧一下:

 new一個對象:

跟以前同樣,將最頂層操做數棧的值進行復制,往下:

其中sipush官網解釋以下:

這裏有一個細節須要注意:源代碼中的999實際上是一個int類型的,以下:

可是在字節碼中999實際上是屬於short類型範圍以內,因此是當一個short類型處理了。

調用ServerSocket的構造方法及父類的,很少說比較容易理解。

看一下它官網的解釋:

也就是將引用賦給了serverSocket變量。

 

官網的解釋:

其實對於方法的調用方式都是基於操做棧的,因此有大量的入棧和出棧的一些操做在裏面的。

發現這對應於代碼:

因爲catch塊中沒有寫代碼,因此直接就到了finally了。

也就是finally這個關鍵字嘛。

調用打印實例方法。

接下來發現有大量的goto助記符:

也就是對於異常在字節碼的表現形式是經過goto來將整個執行進行中斷的,爲了能理解這裏面的goto,此時須要先分析一下異常表信息,以下:

其中能夠總體看到「Catch Type」這行,恰好跟我們捕獲的異常能對應上,以下:

其中還有最後一個:

其中理論依據爲:

下面具體來看一下:

發現Start PC和End PC都是從0到26,先來回顧一下這兩個的含義:

 也就是表示:

其實對應於源代碼就是try的部分,以下:

這段代碼拋出任何異常都會有相應的異常表項來處理,我們一一來看一下:

也就是說若是代碼發現了FileNotFoundException異常時,則會由37這個位置的Handler PC來處理異常,那37對應於哪呢?

而astore_1表示:

那如何理解呢?來看下源代碼:

很明顯當生成異常時會將異常對象賦值給這個ex,因此就會有這樣的一個引用賦值操做,因爲這個catch塊中沒有寫任何代碼,因此就立馬就執行到了finally塊了,也就是對應於這段助記符:

最後又有一個goto了,以下:

第一個異常的整個字節碼流程分析完以後,其它兩個就基本相似了,我們來過一遍:

當發生異常則會跳到49的Handler PC,以下:

接着再看第三個異常:

而後會跳到61,看一下,同樣的套路:

好了對於我們本身捕獲的異常的內部處理機制已經很是之清楚了,剩最後一種異常狀況下,以下:

從程序角度照理應該是Exception已經包含全部能夠捕獲的異常了,可是從字節碼角度並不這樣認爲,因此這也是爲啥會有這麼一個異常的狀況出現,表示處理上面我們手動捕獲的以外不可能處理的異常,這是編譯器自動爲咱們生成出來的,我們來看一下73是啥:

只是其中發現了一個athrow,這是個什麼東東:

至此,我們就完全把異常機制相關的東東完完整整的分析完了,下面來總結一下:

Java字節碼對於異常的處理方式:

一、統一採用異常表的方式來對異常進行處理。

二、在以前的JDK 1.4.2以前的版本中並非使用異常表的方式來對異常進行處理的,而是採用特定的指令方式。【瞭解既可】

三、當異常處理存在finally語句塊時,現代化的JVM採起的處理方式是將finally語句塊的字節碼批接到每個catch塊後面,換句話說,程序中有多少個catch塊,就會在每個catch塊後面重複多少個finally語句塊的的字節碼。從字節碼就能夠得知:

關於異常表就瞭解到這,接下來了解另一個信息,以下:

根據以前的瞭解,咱們也知道這個屬性主要是描述字節碼的位置對應源代碼的行號,便於debug,以下:

下面來一一細看一下:

字節碼0處對應源代碼13行,瞅一下:

其中的Start PC是指代碼字節碼的起始位置,恰好是對應的。

繼續:

字節碼10對應源代碼14,看一下:

徹底能對應上,繼續再挑一個看,因爲規則是同樣的,就不必徹底一個個對了,知道個大概做用就成:

字節碼49對應源代碼18:

因此經過這個就能夠將字節碼跟源代碼對應起來。

最後再來看一下它:

發現jclasslib中只有3個,而以前在javap -verbose中看到的是有4個,回憶下:

由於目前jcalsslib打開的是一個靜態的class,並不知道是否拋出異常,因此靜態的狀況下就只能看到3個局部變量,javap -verbose上看到的是最大能夠有4個局部變量,也就是一旦運行拋異常了那最終就有4個局部變量啦,沒毛病的!

相關文章
相關標籤/搜索