《深入理解Java虛擬機》讀書筆記,java字節碼文件的這塊定義的數據結構比較多,書講解的很詳細。
一.class文件中的數據格式
字節碼文件是由java源文件經過編譯之后獲得,是以8位字節為基礎單位的二進制流,各個數據嚴格按照順序緊湊地排列在class文件之中,中間沒有任何分割符,當數據項占用8位字節以上的空間時,按照高位在前(大端法)的方式分割成若干個8位字節進行存儲。
class文件中的格式只有倆種數據類型:無符號數和表
無符號數:為基本類型的數據類型,以u1,u2,u4,u8來代表1個字節,2個字節,4個字節,8個字節的無符號數。無符號數可以用來描述“數字、索引引用、數量值或者按照utf-8編碼構成的字符串值。
表:表是由多個無符號數或者其他表作為數據項構成的復雜數據類型。所有表都習慣以“_info”結尾。表用于描述有層次關系的復雜結構的數據。如下:
表中描述的標簽有“類型、名稱、數量”,對于一段由0和1組成的序列來說,有了類型,那么就知道了數據的大小,去讀取數據大小的字節即可,通過名稱可以知道數據所要表達的意思,數量則可以知道有多少個這樣的數據類型。
舉個例子來說的話,有一段序列是代表一張表,其中表中每一項的類型和數量是已經的,且是順序排序的。那么在讀取的時候按照固定的字節去讀取進行解析即可。
二. class文件格式
整個class文件也是一張表。下圖中可以看出編譯之后class文件中包含了常量池、字段表、接口表、屬性表等。
在文件中的存儲如下:
三.常量池
常量池中存放倆大類常量:字面量和符號引用。
字面量:文本字符串、聲明為final的常量值等
符號引用:類和接口的全限定名、字段名稱和描述符、方法的名稱和描述符
常量池的項目類型:
常量池中的每一種類型都是一張表,且結構各不相同。在java編譯期編譯java源文件時,把源文件中的有關類,字段,方法相關的信息全部放入class字節碼的常量池中,class文件中的字段表,方法表中可以通過常量池中的“常量”索引去訪問對應的常量項,拿到類或方法,字段等信息。
java虛擬機在運行java程序時,首先去加載class文件,通過class文件,java虛擬機才知道對象有那些方法,字段,然后去內存分配空間,進行運算。
3.1 CONSTANT_Class_info
class_info表中tag所占1個字節,值為7,代表為class_info。index指向CONSTANT_Utf8_info表,其內容為類的全限定名。
3.2 CONSTANT_Fieldref_info
第一個index是聲明字段的類的CONSTANT_Class_info索引項,通過這個索引可以知道字段是哪個類聲明的。
第二個index是CONSTANT_NameAndType的索引項。
3.3 CONSTANT_NameAndType
CONSTANT_NameAndType中的內容包含了字段的名稱和描述符,描述符用來表示字段的數據類型(基本類型或者對象)。
3.4 CONSTANT_Method_Type_info
四. 字段表
上表中name_index和descriptor_index都是對常量池的引用。name_index代表字段的名稱,descriptor_index代表字段的描述符。
字段表集合中不會列出從超類或者父接口中繼承而來的字段。
內部類中為了保持對外部類的訪問性,會自動添加指向外部類實例的字段。
五. 方法表
其中name_index和descriptor_index和屬性表中一樣,代表方法的名稱和方法的描述符。
六.屬性表
6.1 Code屬性
6.2 Exceptions屬性
Exceptions屬性是列舉方法中可能拋出的受查異常,也就是throws關鍵子后面列舉的異常。
6.3 LocalVariableTable屬性
其中local_variable_info表示的方法中的形參和局部變量。start_pc和length表示變量的作用域。
6.4 ConstantValue屬性
ConstantValue屬性的作用是通知虛擬機自動為靜態變量賦值。
static類型的的變量,有倆種賦值方式,一種是在類構造器<clinit>方法中,另一種是通過ConstantValue屬性。Sun Javac編譯器中,如果同時使用final和static來修飾一個變量,并且這個變量的數據類型是基本類型或者String類型的話,就生成Constant屬性來進行初始化。
6.5 InnerClasses 屬性
InnerClasses屬性用于記錄內部類與宿主類之間的關聯。
數據類number_of_classes代表需要記錄多少個內部類,每個內部類的信息都由一個inner_classes_info表進行描述。
- inner_class_info_index和outer_class_info_index都是指向常量池中
CONSTANT_Class_info型常量的索引 - inner_name_index是指向常量池中CONSTANT_Utf8_info型常量的索引,代表這個類的名稱,如果是匿名內部類,那么這項值為0.
- inner_class_access_flags是內部類的訪問標志
6.6 Signature 屬性
Signature屬性記錄的是泛型簽名信息。java語言的泛型采用的是擦除法,在字節碼中,泛型信息都被擦除掉了。JDK1.5之后,任何類、接口、初始化方法或成員的泛型簽名中如果包含了類型變量或者“參數化類型”,則Signature屬性會為它記錄泛型簽名信息。