每一個class位元組碼文件都唯一對應一個類或介面,class文件中記錄中類或介面的基本信息,但反之不成立,不是每一個類或介面都有一個唯一對應的位元組碼文件,首先類或介面的位元組碼可以不以文件的方式存儲,可以直接從記憶體中生成位元組碼,而不產生.class文件,動態代理的原理就是直接記憶體中生成位元組碼流,根據加 ...
hello world
class位元組碼文件
每一個class位元組碼文件都唯一對應一個類或介面,class文件中記錄中類或介面的基本信息,但反之不成立,不是每一個類或介面都有一個唯一對應的位元組碼文件,首先類或介面的位元組碼可以不以文件的方式存儲,可以直接從記憶體中生成位元組碼,而不產生.class文件,動態代理的原理就是直接記憶體中生成位元組碼流,根據載入位元組碼流進行類載入操作,類實例化,生成代理對象。
位元組碼文件記錄的信息:魔術,class文件主次版本,常量池數量及常量池表,類或介面的訪問標誌,類索引,超類索引,介面數量及介面表,欄位數量及欄位表,方法數量及方法表,屬性屬性及屬性表,jvm中使用類c結構體表示每一種屬性,結構體中類型種類有兩種,無符號數及表,以 _info結尾表示表,以 u1,u2,u4,u8分別表示1位元組,2位元組,4位元組,8位元組無符號數
ClassFile{
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count];
u2 acc_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
魔術:四個位元組,用於定義此位元組碼文件是否符合虛擬機規範,保證位元組碼文件不會威脅虛擬機的安全,若為cafebabe則表示位元組碼符合虛擬機規範
主次版本號:四個位元組,前兩位元組表示次版本號,後兩位元組表示主版本號,用於定義編譯的位元組碼文件格式版本,低版本虛擬機拒絕運行高版本位元組碼文件,但高版本虛擬機會向下相容低版本位元組碼文件
常量池數量及常量池表:這部分主要統計類或介面的字面量和符號引用,用於每個類或介面擁有的字面量和符號引用屬性不一定相同,所有需要兩個位元組的長度來表示常量池數目,常量池數目計數從1開始,比如類或介面中總共有兩個字面量符號引用,則常量池數目為2,註意,不是從0開始計數,0可能另有用處,可以用來表示類或介面中未出現的引用,用來表示超級父類java.long.Object全限定名的索引,常量池表是一個數組,一共有18種類型,每一種類型有一個tag屬性與之對應,constant_utf8_info用於表示文本字元串,類和介面全限定名,欄位名稱及描述符,方法名稱及描述符等常量信息,constant_integer_info用於存儲int類型的常量信息,只存儲int類型的值,不存儲其他符合引用信息,比如 final int a=1 符號引用信息為a,值為1,constant_float_info用於存儲float類型常量信息,也是只存儲float值,不存儲引用信息,constant_long_info用於存儲long類型的常量信息,constant_double_info用於存儲double類型的常量信息,constant_class_info用於存儲指向常量池列表constant_unf8_info類和介面全限定名的有效引用,constant_string_info用於存儲指定常量池列表constant_utf8_info某常量項的有效索引,指向文本字元串,constant_fieldref_info用於存儲指向常量池列表constant_class_info常量項和constant_nameandtype_info常量項的有效索引,constant_methodref_info用於存儲指向常量池列表constant_class_info常量項和constant_nameandtype_info常量項的有效索引,constant_interfacemethodref_info用於存儲指向常量池列表constant_class_info常量項和constant_nameandtype_info常量項的有效索引,constant_nameandtype_info用於存儲指向常量池列表constant_utf8_info常量項的有效索引,可以通過所有找到對應類及描述符,constant_methodtype_info用於存儲指向常量池constant_utf8_info常量項,表示方法類型,找到對應的方法描述符,constant_methodhandle_info用於表示方法句柄,屬性reference_kind表示方法句柄的類型,1-4表示為欄位創建的方法句柄,5-8表示為類方法(構造、實例、靜態)創建的句柄,9表示為介面方法創建的句柄,reference_index屬性指向根據reference_kind對應的常量池列表,constant_invokedynamic_info用於存儲當前位元組碼文件中引導方法bootstrap_method數組的有效索引和指向常量池constant_nameandtype_info常量項的有效索引
constant_utf8_info{
u1 tag;
u2 length;
u1 bytes[length];
}
constant_integer_info{
u1 tag;
u4 bytes;
}
constant_float_info{
u1 tag;
u4 float;
}
constant_long_info{
u1 falg;
u8 long;
}
constant_double_info{
u1 tag;
u4 double;
}
constant_class_info{
u1 tag;
u2 name_index;
}
constant_string_info{
u1 tag;
u2 string_index;
}
constant_fieldref_info{
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
constant_mathodref_info{
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
constant_interfacemathodref_info{
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
constant_nameandtype_info{
u1 tag;
u2 class_index;
u2 descriptor_index;
}
constant_methodhandle_info{
u1 tag;
u2 reference_kind;
u2 reference_index;
}
constant_methodtype_info{
u1 tag;
u2 descriptor_index;
}
constant_invokedynamic_info{
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
訪問標誌:兩個位元組,用於定義位元組碼文件所表示的類或介面的訪問許可權,如判斷是類還是介面,類是否被abstract修飾,類是否被final修飾, acc_interface表示是介面,acc_annotation表示是註解類型,acc_enum表示是枚舉類型,acc_public 表示類或介面是public訪問許可權,acc_final表示類不允許被繼承,acc_abstract表示類為抽象類,acc_super表示類調用實例方法時需進行特殊操作
類索引及父類索引:四個位元組,用於存儲指向常量池constant_class_info對應的有效索引,而constant_class_info存儲常量池列表的constant_utf8_info常量項索引,根據此索引可找到類和父類的全限定名
介面數量及介面表:介面屬性用於存儲當前類或介面的直接超類介面數量,介面表是一個數組,記住,只有常量池表從1開始計數,其餘都是從數組下表0開始計數,介面表數組的每一個數組元素存儲此類或介面的直接超類介面的有效索引,根據此索引找到constant_class_info對應的常量項,根據constant_class_info可找到對應直接超類介面的全限定名
欄位數量及欄位表:欄位數量用於存儲類或介面的欄位數目,包括類欄位和實例欄位,欄位表為一個數組,每一個數組元素都相當於一個field_info結構的對象,field_info結構包含欄位完整信息:欄位標識符,欄位訪問修飾符,欄位是類欄位還是實例欄位,欄位是否為常量等,註意:此處欄位表示當前類或介面的欄位,不包括從超類或介面繼承的欄位,java語法規範不允許同一個類或介面中出現同一欄位名的不同欄位,但是class文件中卻可以允許出現相同欄位名的不同欄位,只有欄位的描述符不同即可,field_info結構屬性:access_flags用於存儲欄位的訪問標誌,acc_private,acc_protected,acc_public,acc_final,acc_static,acc_volatile等,註意:acc_final與acc_volatile不能同時出現在同一欄位,name_index指向常量池constant_utf8_info常量項的有效索引,獲取當前欄位的簡單名稱,descriptor_index指向常量池constant_utf8_info常量項的有效索引,獲取當前欄位的描述符,attribute_count,attributes[attributes_count]這兩項表示欄位的屬性信息,用於描述欄位相關信息,attribute數組每一個元素都是一個attribute_info結構的元素
field_info{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attribuyes_count];
}
方法數量及方法表:方法數量用於存儲當前類或介面的方法數目,包括實例方法,類方法,抽象方法,方法表是一個數組,每一個數組元素都是一個method_info結構,method_info結構包含方法的完整信息:方法描述符,訪問修飾符,是否為final方法,是否為abstract方法等,註意:此處的方法數組只是表示當前類或介面的所有方法,並不包括從超類及父介面繼承來的方法,java語法規範java類或介面中不允許出現方法簽名完全一樣的方法同時出現,會編譯報錯,而位元組碼層面卻允許方法簽名完全相同的方法同時出現,只需要保證方法的返回值類型不同,method_info結構屬性與field_info一致,但acc_flags類型不盡相同,註意acc_abstract不能與acc_final,acc_static,acc_private,acc_synchronized,acc_native同時使用,介面方法中只能使用acc_public,acc_abstract,此處我有一個疑問,介面中default方法有沒有對應的訪問標誌,註意:<init>方法只能使用acc_private,acc_protected,acc_public訪問標誌
method_info{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attribuyes_count];
}
屬性數量及屬性表:屬性數量表示當前位元組碼文件中attribute_info表數目,屬性表是一個數組,每一個數組元素都是attribute_info結構,attribute_info結構表示屬性的完整信息:第一項指向常量池constant_utf8_info某常量項的有效索引,根據此索引可找到屬性對應名稱,屬性可以出現在classFile,欄位表,方法表中,用以描述相關信息,attribute_info結構完整信息:attribute_name_index指向常量池constant_utf8_info常量項的有效索引,獲取屬性名稱,attribute_length用於指明info數組長度,info[attribute_length]用於存儲屬性的數據信息,必須實現的數據信息:Code,ConstantValue,Exceptions, code屬性用於描述method_info的具體相關信息,attribute_name_index指向常量池constant_utf8_info常量項的有效索引,獲取屬性名稱,即code,attribute_length表示attribute表示attribute_info長度,不包括attribute_name_index和attribute_length的初始6位元組,max_stack描述當前方法最大棧深度,max_locals描述當前方法的局部變數表,code_length表示code數組長度,code[]表示當前方法編譯後的位元組碼, ContantVaue位於field_info結構中,用於通知虛擬機對類變數進行初始化,即欄位需要被acc_static修飾,當前類常量不需要ContantValue通知虛擬機執行初始化,早就執行好了,實例欄位此時不需要初始化
attribute_info{
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
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;
exception_info exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
constantvalue_attribute{
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
簡單名稱與描述符:
簡單名稱是指欄位或方法的簡單的一種描述,比如person class:private String name欄位簡單名稱為name,Object class:public String toString()方法簡單名稱為toString,註意:欄位或方法簡單名稱不允許出現 . : / [ 等ASSIC或Unicode字元表示形式
描述符一般指欄位或方法的類型,欄位描述符表示欄位類型描述,方法描述符表示參數描述與返回值描述,如:person class:private String name欄位描述符為Ljava.lang.Object,com.test.Person class:setName(String name)方法描述符為(Ljava.lang.String)V,註意:其中V表示返回值為void類型,如果參數為void則表示為()Ljava.lang.Object,表示無參的返回值為java.lang.Object引用類型的方法描述符
欄位描述符解釋:B byte 位元組類型,Z boolean 布爾類型,C char 字元類型,S short 短整型,I 整型,L long 長整型,F float 單進度浮點類型,D double 雙精度浮點類型,L reference 對象引用類型,[ reference 數組引用類型
constant_mathodref_info{
u1 tag;
u2 class_index;
u2 name_and_type_index;
}