上篇文章提到過在Class結(jié)構(gòu)表中,屬性表存在于Class表,字段表和方法表中,是為了 「描述額外的信息」 。
?屬性表在《JAVA虛擬機(jī)規(guī)范》中并沒有像其他數(shù)據(jù)一樣做嚴(yán)格的限制,我們甚至可以自己實(shí)現(xiàn)一個(gè)編譯器往Class結(jié)構(gòu)的屬性表中注入額外的屬性信息,虛擬機(jī)運(yùn)行時(shí)會(huì)忽略掉它識(shí)別不了的屬性。
?
屬性表屬性總覽
這張圖中按Class結(jié)構(gòu),字段表,方法表這三個(gè)維度進(jìn)行了區(qū)分標(biāo)注,將 「三者共有的屬性」 提取到最頂部的 「黃色橢圓」 中, 「藍(lán)色」 代表各自屬性表 「額外用到的屬性」 , 「紅色」 代表 「Code屬性中引用的其他屬性的集合」 。
引自《深入理解JAVA虛擬機(jī)》,讀者也可以看這下面的兩張圖:
屬性結(jié)構(gòu)
首先表結(jié)構(gòu)中的前兩個(gè)字節(jié)說明該屬性是叫什么名字,也就是什么類型的屬性,最終指向常量池中的CONSTANT_Utf8_info類型的常量。
?eg:Code,ConstantValue,SourceFile。。。等
?
接著用四個(gè)字節(jié)描述屬性值的長(zhǎng)度,也就是說明屬性值所占用的字節(jié)數(shù);
?除了第一個(gè)屬性名稱信息和該屬性描述的屬性長(zhǎng)度,其他的就是屬性值了,因此該值(屬性值長(zhǎng)度)固定為 整個(gè)屬性表長(zhǎng)度-6個(gè)字節(jié)
?
最后列出屬性信息,有多少屬性信息呢?前四個(gè)字節(jié)已經(jīng)列出了這個(gè)屬性包含多少個(gè)屬性,因此最后描述各個(gè)屬性的信息。
前兩個(gè)屬性是所有屬性都共有的,之后就不進(jìn)行講解了。
常見屬性
Code
?只有方法內(nèi)有方法體的方法表才會(huì)有這項(xiàng)屬性,像抽象方法,非defult接口方法是沒有這個(gè)屬性的(沒有方法體)
?
「該屬性用于存放 操作數(shù)棧最大深度, 本地變量表最大占用存儲(chǔ)空間, 方法中Catch塊定義的異常類型和數(shù)量, 編譯后方法體的字節(jié)碼指令和指令長(zhǎng)度, 還有其他屬性」
首先先看下Code屬性表的結(jié)構(gòu):
1.「max_stack操作數(shù)棧最大深度」
先看下之前的這篇文章,Java程序運(yùn)行是基于棧的操作,就是說的該項(xiàng)屬性。
通過指令從本地變量表中拿數(shù)據(jù)放到棧頂;將數(shù)據(jù)從棧頂保存到本地變量中;對(duì)棧頂兩個(gè)值進(jìn)行運(yùn)算后將結(jié)果壓入棧頂;將棧頂?shù)闹底鳛榉祷亟Y(jié)果return.....等等這些都是通過操作數(shù)據(jù)結(jié)構(gòu)棧來完成的。
?這項(xiàng)屬性描述了方法中操作數(shù)棧的最大深度,虛擬機(jī)運(yùn)行時(shí)會(huì)根據(jù)這項(xiàng)屬性來分配棧幀中操作數(shù)棧的最大深度。
?
2.「max_locals局部變量表所需空間」
局部變量表最大占用的存儲(chǔ)空間,存儲(chǔ)的單位用的是Slot(變量槽),一個(gè) Slot占用空間大小為32位。
存儲(chǔ)范圍:比如方法的參數(shù),Catch塊中定義的異常類型,方法體中定義的局部變量。
?對(duì)于方法參數(shù)來說,根據(jù)實(shí)例方法(通過對(duì)象才能訪問)和靜態(tài)方法(通過類名就可以直接訪問)又有不同;實(shí)例方法的參數(shù)中第一個(gè)是this,該變量會(huì)在編譯時(shí)加入,而靜態(tài)方法則沒有這個(gè)變量。
?
存儲(chǔ)空間:對(duì)于小于32位的數(shù)據(jù)類型用一個(gè)變量槽,大于32位的用多個(gè)變量槽存儲(chǔ)(比如小于64位的數(shù)據(jù)類型double和long用兩個(gè)變量槽存儲(chǔ))。優(yōu)化:對(duì)變量限定作用域,如果變量超出了作用域范圍,那么存儲(chǔ)該變量的Slot進(jìn)行存儲(chǔ)其他的變量,也就是重用變量槽。
?根據(jù)同時(shí)生存的最大局部變量數(shù)量和類型計(jì)算出max_locals的大小。
?
3.「code_length,code屬性用于表述方法體編譯后的字節(jié)碼指令長(zhǎng)度和字節(jié)碼指令流」
?字節(jié)碼指令流,一個(gè)字節(jié)代表一條指令,即每條指令就是一個(gè)u1類型的單字節(jié);u1數(shù)據(jù)類型取值范圍是0X00~0XFF,對(duì)應(yīng)十進(jìn)制為0到255。即u1可以表達(dá)256條指令,目前使用的大約只有200條
?
?方法體中不允許超過65535條字節(jié)碼指令,如果超出了編譯器拒絕編譯;但是code_length用的是u4長(zhǎng)度值,可以達(dá)到2的32次冪,相當(dāng)于指令長(zhǎng)度只用了一半(u2長(zhǎng)度)。
?
4.「exception_table_length,exception_table用于描述方法塊中Catch塊定義的異常數(shù)量和類型」
?如果方法體內(nèi)部沒有catch塊則length為0,后面的字節(jié)不描述exception_table
?
在這里插入圖片描述
?Exception table:
from to target type
0 5 10 Class java/lang/Exception
0 5 21 any
10 16 21 any
?
Exceptions
該屬性和上面提到的exception_table描述的信息不一樣,exception_table是描述方法體中Catch塊中定義的異常數(shù)量和類型;而該項(xiàng)屬性是描述方法throws的異常數(shù)量和類型,通俗來說就是調(diào)用該方法需要catch的異常,也叫作受查異常。
?因此上面的excepitons_table描述方法體內(nèi)部Catch的異常,Exceptions描述方法拋出的異常
?
結(jié)構(gòu):
LineNumberTable
?用于描述Java代碼行號(hào)和字節(jié)碼行號(hào)的對(duì)應(yīng)關(guān)系,該項(xiàng)屬性可選擇是否輸出
?
?用處:當(dāng)執(zhí)行某段字節(jié)碼指令拋出異常時(shí)可以根據(jù)這個(gè)對(duì)應(yīng)關(guān)系,提示開發(fā)者Java代碼對(duì)應(yīng)的行號(hào)。
?
結(jié)構(gòu)
-
JAVA
+關(guān)注
關(guān)注
19文章
2969瀏覽量
104789 -
Class
+關(guān)注
關(guān)注
0文章
53瀏覽量
19745 -
JVM
+關(guān)注
關(guān)注
0文章
158瀏覽量
12236
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論