我們知道一個Class文件對應着一個接口或者註解的類,但是他們並不一定定義在文件裏,也可以直接由類加載器生成。
Java虛擬機定義了專門的數據類型來表示class文件的內容,他們包括u1,u2,u4表示1,2,4個無符號數
一 Class文件結構
在Class文件中,各個項按照嚴格順序連續存放的,他們之間沒有任何填充或者對齊做爲分隔符。
表由任意數量的可變長度的項組成,表示Class文件內容一系列複合結構,如圖所示:
二 文件結構-魔數 和 版本號
每一個class文件頭4個字節叫做魔數,他的作用就是確定這個文件是不是一個能被虛擬機接收的Class文件。
很多格式的文件都使用魔數而不是擴展名來識別,比如圖片格式JPG 或者 PNG等。使用魔數而不使用擴展名是基於安全的考慮,因爲文件擴展名是可以隨意更改的。
Class文件的魔數值就是CAFEBABE.
然後接着4個字節就是Class文件版本號:
5-6字節時小版本號(u2),7-8字節時主版本號(u2),JDK能向下兼容低版本的class文件,但是不能執行高於其版本的class文件。
通過16進制轉換成10進制,得出最小版本好0 主版本號52(JDK1.8)
三 文件結構-常量池
3.1 常量池計數器 constant_pool_count
常量池計數器 = 常量池表中的成員數 + 1. 常量池的索引值index,只有在index > 0 && index <constant_pool_count時纔會認爲是有效的。
3.2 常量池constant_pool
常量池是一種表結構,它包含了Class文件結構及其及其子結構中引用的所有字符串常量,類或者接口名、字段名或者其他常量。
3.2.1 常量池表中類型的共同特點
# 第一個字節作爲類型標記(tag值),用於確定該項的格式,表明是什麼類型的常量,比如tag值爲3表明是CONSTANT_INTEGER類型。
# 如果是字符串,還有length項表示字符串長度,然後bytes項表示字符串內容
# 有的是index,index就是當前不是具體的常量值,他們一般是引用其他常量類型。比如CONSTANT_STRING{
u1:tag,
u2: string_index(指向CONSTANT_UTF8)
}
#3 = String #20
#20 = Utf8 Static Type Convert
3.2.2 常量池表裏的常量類型
基本數據類型
CONSTANT_STRING {
u1 tag;
u2string_index;
}
tag 指的就是8
string_index 指的就是對CONSTANT_UTF8的索引值
CONSTANT_INTEGER {
u1 tag;
u4bytes;
}
tag 指的就是3
bytes指的是int類型的常量值
CONSTANT_FLOAT {
u1 tag;
u4bytes;
}
tag 指的就是4
bytes指的是float類型的常量值
CONSTANT_LONG {
u1 tag;
u4high_bytes;
u4low_bytes;
}
tag 指的就是5
high_bytes和low_bytes共同表示LONG類型常量
CONSTANT_DOUBLE{
u1 tag;
u4high_bytes;
u4low_bytes;
}
tag 指的就是6
high_bytes和low_bytes共同表示DOUBLE類型常量
CONSTANT_UTF8 {
u1 tag;
u2length;
u1bytes[length];
}
tag 指的就是1
length指明瞭byte數組的長度
其他類型
字段或者方法名字和描述符類型
CONSTANT_NameAndType {
u1 tag;
u2name_index;
u2descriptor_index;
}
tag 值爲12
name_index必須是對CONSTANT_UTF8的引用,即名字
descriptor_index 必須是對CONSTANT_UTF8的引用,即字段或者方法描述符
類或者接口類型
COSNTANT_CLASS {
u1 tag;
u2name_index;
}
tag 值爲7
name_index必須是對CONSTANT_UTF8的引用,即類或者接口名字
字段類型
COSNTANT_Fieldref{
u1 tag;
u2class_index;
u2 name_and_type_index;
}
tag值爲9
class_index 索引值必須指向CONSTANT_CLASS的,即這是哪一個類型上的屬性
name_and_type_index 索引值必須指向CONSTANT_NameAndType,即當前字段名字和描述符
方法類型
COSNTANT_Methodref{
u1 tag;
u2class_index;
u2name_and_type_index;
}
tag值爲10
class_index 索引值必須指向CONSTANT_CLASS的,即這是哪一個類型上的方法
name_and_type_index 索引值必須指向CONSTANT_NameAndType,即當前方法名字和描述符
接口方法類型
CONSTANT_InterfaceMethodref{
u1 tag;
u2class_index;
u2name_and_type_index;
}
tag值爲11
class_index 索引值必須指向CONSTANT_CLASS的,即這是哪一個接口的方法
name_and_type_index 索引值必須指向CONSTANT_NameAndType,即當前方法名字和描述符
方法句柄類型
CONSTANT_MethodHandle {
u1 tag;
u2reference_kind;
u2reference_index;
}
tag值爲15
reference_kind [1-9]範圍內,表示方法句柄類型
name_and_type_index 索引值必須指向CONSTANT_NameAndType,即當前方法名字和描述符
若reference_kind 爲1,2,3,4 即REF_getField,REF_getStatic,REF_putFiled,REF_putStatic,那麼此處成員必須是CONSTANT_Fieldref結構,表示某個字段.
若reference_kind 爲5,8 即REF_invokeVirtual或者REF_newInvokeSpecial,那麼此處成員必須是CONSTANT_Methodref結構,表示某個方法或者構造器,如果是8名稱必須是<init>
若reference_kind 爲6,7 即REF_invokeStatic或者REF_invokeSpecial,且JDK版本1.8以下,那麼此處成員必須是CONSTANT_Methodref或者CONSTANT_InterfaceMethodref結構,表示接口中某個方法
若reference_kind 爲9 即REF_invokeInterface那麼此處成員必須是CONSTANT_InterfaceMethodref結構,表示接口中某個方法
方法類型
CONSTANT_MethodType{
u1 tag;
u2descriptor_index;
}
tag值爲16
descriptor_index 必須是對CONSTANT_UTF8的引用,即字段或者方法描述符
動態調用類型
CONSTANT_InvokeDynamic{
u1 tag;
u2bootstrap_method_attr_index;
u2name_and_type_index;
}
tag值爲18
bootstrap_method_attr_index: 必須是當前class文件中引導方法表
name_and_type_index 索引值必須指向CONSTANT_NameAndType,即當前字段名字和描述符
四 文件結構-訪問標誌
在常量池結束後,緊接着2個字節代表訪問標誌access_flags,這個標誌用於識別一些類或者接口層次的訪問信息。
包括這個Class是接口還是類,是否定義爲public類型,是否定義爲abstract類型,如果是類的話是否聲明爲final.
五 文件結構-字段
field {
u2access_flags;
u2name_index;
u2descriptor_index;
u2attributes_count;
attribute_infoattributes[attributes_count];
}
access_flags: 表示字段的訪問權限和基本屬性,比如是public 是不是 final 是不是抽象等
name_index: 字段名字,必須指向一個CONSTANT-UTF8類型的結構
descriptor_index:字段描述符,必須指向一個CONSTANT-UTF8類型的結構
attributes_count:表示附加屬性的數量
attribute_info:附加屬性
六 文件結構-方法
method {
u2 access_flags;
u2name_index;
u2descriptor_index;
u2attributes_count;
attribute_infoattributes[attributes_count];
}
access_flags: 表示方法的訪問權限和基本屬性,比如是public 是不是 final 是不是抽象等
name_index: 方法名字,必須指向一個CONSTANT_UTF8類型的結構
descriptor_index:方法描述符,必須指向一個CONSTANT_UTF8類型的結構
attributes_count:表示附加屬性的數量
attribute_info:附加屬性
七 文件結構-描述符
描述符是一個描述字段或者方法類型的字符串比如方法返回類型是什麼,接收參數類型是什麼等
public void add(int a, int b) {
}
descriptor: (II)V
flags: ACC_PUBLIC
public List<String> add(String[] arr) {
List<String>list = new ArrayList<String>();
if (arr!= null || arr.length > 0) {
for(int i =0; i < arr.length; i++) {
list.add(arr[i]);
}
}
returnlist;
}
descriptor: ([Ljava/lang/String;)Ljava/util/List;
flags: ACC_PUBLIC