中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Java字節(jié)碼結(jié)構(gòu)剖析三:方法表

2018-11-20    來源:importnew

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

這里給大家介紹一款字節(jié)碼分析小工具——jclasslib bytecode viewer。它可以將字節(jié)碼文件結(jié)構(gòu)化的展現(xiàn)給我們看。

緊接著上篇『字段表』的分析。后面的分析輪到了『方法表』。

方法表結(jié)構(gòu)

  • u2 method_count:方法計(jì)數(shù)器,methods_count 的值表示當(dāng)前 class 文件 methods[]數(shù)組的成員個數(shù)。
  • method_info methods[methods_count]: 方法表,methods[]數(shù)組中的每個成員都必須是一個 method_info 結(jié)構(gòu)的數(shù)據(jù)項(xiàng),用于表示當(dāng)前類或接口中某個方法的完整描述。
  • method_info 結(jié)構(gòu):
method_info {
	u2 access_flag                     1
	u2 name_index                      1
	u2 descriptor_index                1
	u2 attribute_count                 1
	attribute_info attributes[attribute_count]
}

方法表的具體解析

知道方法表的組成結(jié)構(gòu),我們就可以直接對照著字節(jié)碼文件去解析了。依然是前文用的java代碼示例產(chǎn)生的字節(jié)碼文件。緊接在『字段表』后面的16進(jìn)制是0×0004=4。即該類有4個成員方法!看源代碼:

public class MyTest2 {
    String str = "Welcome";
    private int x = 5;
    public static Integer in = 10;

    public static void main(String[] args) {
        MyTest2 myTest2 = new MyTest2();
        myTest2.setX(8);

        in = 20;
    }
    public void setX(int x) {
        this.x = x;
    }
}

源代碼中,我們只定義了2個成員方法!但是字節(jié)碼卻說有4個方法。我們用jclasslib小工具打開看一下。展示如下:

這樣就一目了然了,其實(shí)字節(jié)碼里除了我們自己顯示定義的2個方法?main?和?setX。Java編譯器生成字節(jié)碼的時候默認(rèn)又幫我們生成了2個方法?<init>?和?<clinit>。

<init>方法就是默認(rèn)的構(gòu)造方法。我們知道,一個類必須要有至少一個構(gòu)造方法,用來完成類的實(shí)例化過程。當(dāng)我們沒有顯示去給一個類定義一個構(gòu)造方法時,Java編譯器在為生成字節(jié)碼文件時,會默認(rèn)給它生成一個默認(rèn)的構(gòu)造方法。
<clinit>方法是類的構(gòu)造器。是類初始化階段要執(zhí)行的方法,它的職責(zé)就是為類的靜態(tài)變量賦初始值(由程序員定義的那個初始值,在我們的源碼中就是靜態(tài)變量in的初始值10),或者如果類中有靜態(tài)代碼塊,那就并按順序執(zhí)行靜態(tài)代碼塊的代碼。

所以,當(dāng)一個類有靜態(tài)變量或者靜態(tài)代碼塊的時候,Java編譯器會為這個類的字節(jié)碼里生成一個<clinit>方法,在類初始化階段去執(zhí)行!

這就是為什么代碼中我們只定義了2個方法,但生成的字節(jié)碼里卻有4個方法的原因了。

分析第一個方法。先看看方法表的部分16進(jìn)制的信息,如下:從0×004開始。

首先是方法的access_flag(訪問標(biāo)志位),即0×0001。說明此方法是public。接著是方法的name_index(指向常量池的索引,代表方法的全限定名稱),0×0011=17。我借助jclasslib小工具可以查到方法名稱是<init>,就是Java編譯器默認(rèn)生成的構(gòu)造方法。然后,是該方法的描述符信息descriptor_index,0×0012=18,同樣可以查到()V。這個描述符說明我們的方法是無參的『()』。且無返回值『V』。完美符合我們構(gòu)造方法的定義。

屬性表分析

我們再看看它的屬性個數(shù),attributes_count的項(xiàng)的值表示這個方法的附加屬性的數(shù)量。0×0001=1,說明這個方法只有一個附加屬性。那后面就是對屬性表的分析了。我們先看一下屬性表的結(jié)構(gòu):

attribute_info {
	u2 attribute_name_index;
	u4 attibute_length;
	u1 info[attibute_length]
}

所以,0×0013=19。表示的就是這個屬性的名字在常量池中的索引。查閱得,該屬性的名字是『Code』。Code屬性很重要,因?yàn)镴ava程序方法中的代碼經(jīng)過javac編譯之后形成字節(jié)碼存在了Code屬性內(nèi)。在這里,我們通過jclasslib先查看一下Code屬性里有什么。

紅框里的助記符就是<init>方法里要執(zhí)行的代碼邏輯!

Code屬性

  • code屬性的作用是保存該方法的結(jié)構(gòu),如所對應(yīng)的字節(jié)碼。
Code_attribute {
	u2 attribute_name_index;
	u4 attribute_length;
	u2 max_stack;
	u2 max_locals;
	u4 code_length;
	u1 code[code_length];
	u2 exception_table_length;
	{   u2 start_pc;
		u2 end_pc;
		u2 handler_pc;
		u2 catch_type;
	} exception_table[exception_table_length];
	u2 attributes_count;
	attribute_info attributes[attributes_count];
}
  • Java程序方法體中的代碼經(jīng)過Java編譯處理后,最終變成字節(jié)碼指令存儲在Code屬性中。Code屬性出現(xiàn)在方法表的屬性集合中,但是并非所有方法都有這個屬性。例如接口或者類中的抽象方法就不存在Code屬性。

Code屬性其實(shí)是一個結(jié)構(gòu)比較復(fù)雜的屬性表。這里就不做過多描述,打算后面抽個時間用一篇博客來說說它。其實(shí)方法表的<init>方法到此,分析得差不多了。接下來,大家可以再對照一遍,自己去把每個方法都分析一遍,加深印象。

標(biāo)簽: ssl 代碼

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:FutureTask在線程池中應(yīng)用和源碼解析

下一篇:Java字節(jié)碼結(jié)構(gòu)剖析二:字段表