類文件(.class
文件擴展名)是包含Java字節碼 ByteCode
的文件,可以在Java虛擬機上執行,每個類文件包含了一個類,接口或者模塊(Java 9)的定義
Java程序(.java
文件)可以通過 Java compiler 生成字節碼文件,其他基于JVM的語言也都可以通過自己的編譯器生成字節碼文件,例如Scala,Groovy等
JVM是與平臺無關的,類文件可以在多個平臺上執行,這使得相應的語言也與平臺無關。
Class類文件的結構
類文件由8位字節流組成, 多字節數據使用big-endian的方式存儲
類文件是按照ClassFile
結構生成的字節流,字段連續存儲,沒有任何填充或對齊。
Class文件格式采是用類C的結構符號表示的偽結構存儲數據,有兩種數據類型,無符號數(u1,u2,u4,u8)和表(*_info)
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_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];
}
Class 文件中涉及類/方法等名稱和描述
名稱
Binary Class and Interface Names
全限定名稱,也叫二進制名稱
例如 Thread
正常的二進制名稱為 java.lang.Thread
,但是因為一些歷史原因,內部格式下,.
被替換成了正斜線/
,使用CONSTANT_Utf8_info
結構(即Utf8編碼的字符串常量)表示其為java/lang/Thread
Unqualified Names
非限定名稱,即簡單名稱,例如Thread
描述符
描述符是表示字段或方法類型(type)的字符串,使用modified UTF-8(UTF-8縮略編碼)
Field Descriptors
基本數據類型用一個大寫字符表示,int
對應 I
對象類型使用一個L
加上全限定,末尾加上分號;
表示,Object
對應Ljava/lang/Object;
數組每個維度使用一個前置[
表示,double[][][]
對應[[[D
Method Descriptors
由零個或者多個參數描述符,加上一個返回值描述符組成
( {ParameterDescriptor} ) ReturnDescriptor
Object m(int i, double d, Thread t) {...}
對應
(IDLjava/lang/Thread;)Ljava/lang/Object;
magic & version
魔數magic number :識別類文件格式,值為0xCAFEBABE
版本號:M.m(主版本號M,副版本號 m)
major version從45開始的,每個大版本號向上加1
JDk1.1.* 支持45.0 到 45.65535
JDk1.8.* 支持45.0 到 52.65535
JDk1.k.* 支持主版本號45.0 到 44+k.0 (k>=2)
常量池
常量池數目constant_pool_count,數目等于常量表的條目數+1
常量池constant_pool是一張表,結構化的表示各種字符串常量,類和接口名稱,字段名稱等,表索引為1到constant_pool_count - 1
它的用處在于:Java虛擬機指令不依賴于運行時的布局,編譯時沒有鏈接這一步,所以指令引用的是constant_pool表中的符號信息
通用結構
cp_info {
u1 tag;
u1 info[];
}
表中的每一項都以一個1byte的標志位開頭,指明該項的常量類型,之后是緊跟相應的內容,每種類型都有自己的結構
CONSTANT_Class_info 結構
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
tag :CONSTANT_Class (7)
name_index:是constant_pool
中有效的索引,其對應的位置必定是一個CONSTANT_Utf8_info
結構,表示類或接口的名稱
CONSTANT_Utf8_info 結構
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
tag :CONSTANT_Utf8 (1)
length:長度,限定了最大長度為65535
bytes[]:Modified UTF-8形式的字符串
CONSTANT_Fieldref_info 結構
用于類加載過程中的解析
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Fieldref_info
, CONSTANT_Methodref_info
, CONSTANT_InterfaceMethodref_info
三種常量結構相似, tag
作為標識,class_index
指向相應的類或接口類型信息的常量,name_and_type_index
指向CONSTANT_NameAndType_info
結構,表示方法或字段的名稱和描述符
訪問標志 access_flags
類或接口的訪問權限和屬性的標志掩碼
自身和父類的信息 this_class / super_class
u2類型,指向CONSTANT_Class_info
的索引,父類的索引可以為0(java.lang.Object
沒有父類),可以獲取對應的類名稱
接口信息 interfaces_count / interfaces[]
描述了該類擴展的接口信息,interfaces[i]
都是constant_pool
表中的CONSTANT_Class_info
的索引, 0 ≤ i < interfaces_count
,接口的順序按照源文件中的實現從左向右排列
字段表
fields_count
是fields
表中field_info
結構的數目
field_info
結構代表了類或接口中所有的字段(類變量class variables
(靜態變量),實例變量instance variables
(類實例中包含的變量)),但是不包含他們的父類或者父接口繼承來的字段
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
name_index
:指向CONSTANT_Utf8_info
結構的索引,表示一個有效的非限定名稱
descriptor_index
:指向CONSTANT_Utf8_info
結構的索引,表示字段的描述符
之后是屬性信息,存儲一些額外的信息,例如對于final static int m = 1
,有ConstantValue
屬性,包含靜態變量的賦值信息。
方法表
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
同字段表類似,訪問標識有部分不同
方法中的Java代碼,經過編譯器,編譯成字節碼格式之后,存放在方法的屬性表內的Code
屬性內
方法表中可能會有編譯器自己添加的方法,例如<init>
或<clinit>
屬性表
ClassFile
, field_info
, method_info
, and Code_attribute
結構中,都含有屬性
Java 9共有26種預定義的屬性
每個屬性的名稱用CONSTANT_Utf8_info
表示,屬性的結構如下
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
Code屬性
是可變長度的屬性,包含了一個方法的JVM指令和輔助信息
native
和 abstract
類沒有Code屬性
//Code 屬性的結構
Code_attribute {
u2 attribute_name_index; //對應一個`CONSTANT_Utf8_info `索引,內容是Code
u4 attribute_length;
u2 max_stack; //operand stack 操作數棧的最大深度
u2 max_locals;//局部變量數組的長度
u4 code_length; //長度小于65536
u1 code[code_length];//字節碼指令
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc; //在code數組中的起點和終點[start_pa, end_pc)
u2 handler_pc; //異常處理對應的字節碼起始位置
u2 catch_type;// 是常量池中 CONSTANT_Class_info的索引,表示捕獲的異常類型,為0則處理任何異常
} exception_table[exception_table_length];//異常表
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Exception屬性
聲明所有的受查異常(checked exception,不是派生于Error
和RuntimeException
的其他所有異常)
Exceptions_attribute {
u2 attribute_name_index; //索引指向`CONSTANT_Utf8_info `表示"Exceptions"
u4 attribute_length;
u2 number_of_exceptions;
u2 exception_index_table[number_of_exceptions]; //索引指向`CONSTANT_Class_info`,表示受查異常的類型
}
LineNumberTable
出現在Code屬性的attributes表中,顯示code字節碼和相應java源文件的行號
用于調試,以及拋出異常時,顯示出錯的行號
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{ u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length];
}
LocalVariableTypeTable
局部變量表,出現在Code屬性的attributes表中,用來在調試過程中描述局部變量的具體類型
LocalVariableTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 local_variable_table_length;
{ u2 start_pc; //對應局部變量的開始位置
u2 length;//作用域[start_pc, start_pc + length)
u2 name_index;//名稱
u2 signature_index;//簽名信息,和描述符類似,保留了泛型類型
u2 index;//局部變量在當前棧幀局部變量表中的位置索引
} local_variable_table[local_variable_table_length];
}
SourceFile
記錄源碼文件的名稱
Signature
Signature_attribute {
u2 attribute_name_index; // "Signature"
u4 attribute_length; //必定是2
u2 signature_index; //對應CONSTANT_Utf8_info,表示類,接口,構造器,方法,字段的簽名
}
Java字節碼的方法的特征簽名,包含返回值和受查異常表(詳細信息,參考jvms9 4.7.9.1)
[TypeParameters] ( {JavaTypeSignature} ) Result {ThrowsSignature}
InnerClass
記錄內部類和宿主類之間的關聯
InnerClasses_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 number_of_classes;
{ u2 inner_class_info_index;//內部類或接口信息CONSTANT_Class_info
u2 outer_class_info_index;//外部類或接口信息CONSTANT_Class_info
u2 inner_name_index;//內部類的名稱CONSTANT_Class_info,匿名內部類名稱為0
u2 inner_class_access_flags;
} classes[number_of_classes];
}
ConstantValue
靜態變量相關的一個定長屬性
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
javap
反編譯Class文件,沒有選項時輸出包,類里的protected和public字段和方法
用法:javap [options] classfile
- -verbose 打印細節,可以查看常量表,棧大小,各方法的 locals 及 args 數等
- -p -private 顯示所有的類和成員
- -c 輸出類中各方法的 Java 字節碼的指令
- -s signatures,輸出內部類型簽名
Reference:
Java Language and Virtual Machine Specifications
The Java? Virtual Machine Specification Java SE 9 Edition