.class檔案結構解析
工具
我們可以使用javap -verbose,配合記事本來對照著看位元組碼檔案
.class檔案結構
class檔案通過記事本開啟,可以得到16進位制的一個檔案,其中結構如下:
魔數
4個位元組,魔數固定為cafe baby
副版本號
2個位元組,表示jdk的次版本號
主版本號
主版本號兩個位元組,假設為00 34,它的10進製為52,52代表的是1.8,51代表的是1.7,依此類推
常量池計數器
記錄常量池資料區中常量的數量
常量池資料區
常量池資料區的資料數量是常量池計數器的數量-1。例如:常量池計數器為00 19轉成10進位制即為25,這個時候常量池資料區應該有24個常量。原因是第一個常量池JVM存了null
常量池結構
u1,u2,u4,u8分別代表1個位元組,2個位元組,4個位元組,8個位元組的無符號數
常量池一般存放兩種常量,字面量和符號引用
描述資訊
在JVM規範中,每個欄位或者變數都有描述資訊,描述資訊的主要作用是 資料型別,方法引數列表,返回值型別等.
1)基本引數型別和void型別都是用一個大寫的字元來表示,物件型別是通過一個大寫L加全類
名錶示,這麼做的好處就是在保證jvm能讀懂class檔案的情況下儘量的壓縮class檔案體積.
基本資料型別表示:
B---->byte
C---->char
D---->double
F----->float
I------>int
J------>long
S------>short
Z------>boolean
V------->void
物件型別:前面加一個L,然後把.改為/
String------>Ljava/lang/String;(後面有一個分號)
對於陣列型別: 每一個唯獨都是用一個前置 [ 來表示
比如: int[] ------>[ I,
String [][]------>[[Ljava.lang.String;
用描述符來描述方法的,先引數列表,後返回值的格式,引數列表按照嚴格的順序放在()中
比如原始碼 String getUserInfoByIdAndName(int id,String name) 的方法描述符號
(I,Ljava/lang/String;)Ljava/lang/String;
訪問標識
解析我們的class檔案是類還是介面,是否定義為public的,是否是abstract,是否被final修飾
兩個訪問修飾符直接通過位運算來實現的。
例如現在有一個class檔案訪問標識為00 21。那麼實際它代表的是0x0021 = 0x0020 位運算 0x0001
,即它代表這個class的訪問許可權是ACC_PUBLIC和ACC_SUPER
類索引
描述當前所屬的類,它儲存著常量池中的位置,例如00 03,就代表這個索引指著常量池中第三個常量,那麼第三個常量的名稱就是這個類的名稱。
父類索引
當前類的父類名字,同類索引,存的也是常量池中的位置。
介面計數器
計數,記錄實現了幾個介面
介面資訊計數區
會存位於常量池中的索引,同類索引和父類索引
欄位資訊
同樣的,前兩位為欄位的數量,後面就是n個欄位,它的作用是描述類和介面中宣告的變數,包括類變數和例項變數,但是不包括方法的區域性變數
欄位的結構如下:
假設有個欄位在class檔案中為00 02 00 05 00 06 00 00
所以00 02 表示訪問修飾符號為ACC_PRIVATE
所以00 05 表示的是欄位的名稱 指向的是常量池中第五個常量
所以00 06是我們的欄位的描述符: 指向的是常量池中第六個常量
00 00 表示是屬性表的個數 這裡為0表示後面是沒有屬性表集合
方法資訊
方法與欄位類似,其結構如下:
假設有個方法在class檔案中為 00 01 00 07 00 08 00 01
00 01:表示的是方法的修飾符 表示的是acc_public
00 07:表示的是方法的名稱 表示指向常量池中第7個常量,表示方法的名稱
00 08:方法的描述符號,表示指向常量池第八個常量
00 01表示有一個方法屬性的個數
注意: