天天看點

帶你分析位元組碼-深入了解class(二)

拖了好久啊,終于寫着第二篇啦,第一篇主要是分析了class檔案的常量池結構。class檔案并不是一堆位元組碼的簡單排列,他們都有自己的結構,jvm主要就是對這些結構進行解釋執行的,對于執行次數頻繁的代碼,jvm會生成機器碼以加快執行效率。好了,廢話不多說,接下來繼續分解。以下class檔案依次描述了類,接口;字段;方法;

注:除特殊說明外,下面所寫的0010,0001什麼的都是16進制。

帶你分析位元組碼-深入了解class(二)

1.類,父類,接口索引

在常量池結束之後,接下來的就是類的描述,包括這個類的全限定名,繼承了那些父類,實作了那些接口。

帶你分析位元組碼-深入了解class(二)

0021:0021是通路标志,由0001|0020得到,0001表示類是public修飾,0020表示是否允許使用invokespecial位元組碼指令,在jdk1.2之後編譯出來的都是可以使用的。通路标志是由多個辨別符或運算得到了,标志符有32個。例如final的辨別符為0010 。

0001:類索引,指向第一個常量,第一個指向第二個,為Amethod,表示類的全限定名

0003:父類索引,指向第三個常量,第三個指向第四個,為java/lang/Object,所有類都繼承自這個類

0001:接口數量,實作了一個借口

0005:指向第5個常量,參考第6個常量,java/io/Serializable,實作了序列化接口

2.字段

想想,字段會包含哪些東西,比如作用域,可變性,是靜态變量還是執行個體變量,并發可見性等等,這些确定的可以用标志位表示。而字段的名稱和類型無法确定,是以要用常量池中的值來表示。

0001:字段的個數,這裡隻有一個

0002:字段作用域,和類比較類似,0001表示public,這裡是0002,表示private

0007,0008:常量池的索引,分别對應j和I,在我前面寫的(一)中的代碼就知道了,j就表示字段的名稱,I表示字段的類型。I表示字段類型是int,B表示byte等等。L表示為對象類型,如String類型就是Ljava/lang/String。特别的,數組類型比如String[] 表示方式[[Ljava/lang/String,在前面加了兩個“[”。

0000:字段的屬性表,這裡沒有額外的屬性,數量為0。

3.方法

方法表和字段表的結構完全一緻。

0002:方法個數,這裡表示一個預設的構造方法和自己定義的一個方法

0001:作用域,public

0009,000A:< init >表示執行個體構造器,< cinit >表示類構造器,這裡0009查常量池得知是執行個體構造器,000A方法的描述,要重載一個方法,需要兩個方法有同樣的名稱和不同的特征簽名,特征簽名包括方法的參數,不包括方法的傳回值,也就是說兩個方法,名稱和參數都相同的話,隻有傳回值不同,編譯器仍然認為是一個方法。這樣是不能重載的。()V表示這個方法沒參數,無傳回值。

0001:屬性表數量,一個

000B:常量池索引,Code,接下來是code屬性表

帶你分析位元組碼-深入了解class(二)

接下來就對着上圖的表分析:

0000002F:attribute_length,表示長度為47,從這個位置開始往後數47個位元組都是他的Code屬性部分,

0001:max_stack:操作數棧深度

0001:max_locals:局部變量表所需儲存空間

00 00 00 05:code_length,位元組碼指令長度,接下來的5個位元組都是位元組碼指令,我們看到這個u4類型的長度值,最大值為2^32-1,表示一個方法内理論上給你的指令的最大值,而java規定了實際上方法内的指令不能超過65535,也就是說一個方法寫的很長的話jvm會拒絕編譯,有時候複雜的jsp可能會出現這種情況

2A B7 00 0C B1:這些指令需要對照位元組碼指令表來解釋,有興趣自己下去研究,不在這次的讨論範圍

0000:異常表,為0

0002:屬性表數量,兩個

000E:常量池中查詢,lineNumberTable,表示源碼行号和位元組碼行号的對應關系,不是運作必須

帶你分析位元組碼-深入了解class(二)

00 00 00 06:attribute_length,為6

0001:line_number_table_length,1

0000 0005:對應關系

000F:指向常量池中的#15,localVariableTable

帶你分析位元組碼-深入了解class(二)

00 00 00 0C:attribute_length,為12

0001 :長度為1

帶你分析位元組碼-深入了解class(二)

0000:start_pc,局部變量生命周期開始的位元組碼偏移量

0005:作用範圍覆寫長度

0010:常量池第16個,this,

0011:第17個,LAmethod

0000:局部變量在棧幀中的位置

到此為止,第一個方法構造方法就分析完了,下一個自己定義的那個方法請嘗試着自己解決。和上述分析方法類似。

分析完了第二個方法,最後就是sourceFile屬性了:

帶你分析位元組碼-深入了解class(二)

0001:一個屬性表

0016:常量池第22個,sourceFile

00 00 00 02:長度為2

0017:源碼檔案檔案名,常量池第23個,Amethod.java。

整個分析到此結束,參考深入了解java虛拟機。有沒說清楚的可以去看看這本書或者問我。~~~

帶你分析位元組碼-深入了解class(二)

按照講解整個可以分成這麼幾塊。

繼續閱讀