在上一次【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個局部變量啦,沒毛病的!