一、class 類文件
class文件是一組以8位字節(jié)為基礎(chǔ)的二進(jìn)制流,中間沒有任何分隔符,所以數(shù)據(jù)的含義和順序都被嚴(yán)格限定。
class 文件使用兩種數(shù)據(jù)類型保存數(shù)據(jù):
- 無符號(hào)數(shù)(有符號(hào)數(shù)有正負(fù)之分)
- 表(由無符號(hào)數(shù)和ITA表構(gòu)成)
class文件本質(zhì)就是一張表
二、class類文件結(jié)構(gòu)
- magic num 和class文件版本
- 常量池
主要存放字面量和符號(hào)引用:
字面量:字符串、final常量等
符號(hào)引用:類和接口全限定名、字段名稱和描述符、方法名稱和描述符
常量池中每一個(gè)常量都是一個(gè)表,共14中類型
image.png
const #7 = Asciz <init>;
const #8 = Asciz ()V;
const #9 = Asciz Code;
const #10 = Method #3.#11; // java/lang/Object."<init>":()V
const #11 = NameAndType #7:#8;// "<init>":()V
其中,第11常量,引用了常量7、8組成了NameAndType常量,
常量7是方法名稱,常量8是方法描述符
- 訪問標(biāo)志
標(biāo)識(shí)類或接口的訪問信息(如public、final、annotation等)
各種訪問標(biāo)志求和后,可得出總訪問標(biāo)志 - 類索引、父類索引與接口索引的集合(用以確定類的繼承關(guān)系)
通過常量池中索引表示 -
字段表集合
描述接口或類中聲明的變量(不包括繼承來的字段和局部變量)
image.png
字段和方法描述符:
描述字段的數(shù)據(jù)類型、方法的參數(shù)列表(包括數(shù)量、類型以及順序)
image.png
對(duì)于數(shù)組類型,每一維度使用一個(gè)前置“[”字符描述,如String[][]二維數(shù)組,被記錄為"[[Ljava/lang/String";int[]被記錄為"[I"
-
方法表集合
image.png描述符用來描述方法時(shí),按照先參數(shù)列表,后返回值的順序描述,參數(shù)列表嚴(yán)格按照順序放在一組小括號(hào)()中,如:
void inc() 描述為 ()V
toString() 描述為 ()Ljava/lang/String
請(qǐng)反推 ([CII[CIII)I的方法
方法里的java代碼,經(jīng)編譯后成為字節(jié)碼指令,存放在方法屬性表集合中,名為Code的屬性中
字段名、方法名等,都是通過索引表示,索引指向常量池 -
屬性表集合
在Class文件、字段表、方法表都可以攜帶自己的屬性表集合,用以描述某些場(chǎng)景專有的信息。
Code屬性:
image.png
code指令執(zhí)行過程中的數(shù)據(jù)交換、方法調(diào)用等操作都是基于操作棧的,如invokespecial,這條指令作用是以棧頂?shù)膔eference類型的數(shù)據(jù)所指向的對(duì)象作為方法接收者,調(diào)用此對(duì)象的實(shí)例構(gòu)造器方法、父類方法、private方法。
注意點(diǎn):
- java中,overload除與原方法同名之外,還要求與原方法特征簽名不同,特征簽名就是一個(gè)方法中各個(gè)參數(shù)在常量池中的字段符號(hào)引用的集合,而返回值不包含在特征簽名中。
- this關(guān)鍵字
編譯時(shí)把this關(guān)鍵字的訪問,轉(zhuǎn)換為普通方法參數(shù)的訪問,調(diào)用時(shí)自動(dòng)傳入當(dāng)前實(shí)例。局部變量表中也會(huì)預(yù)留第一個(gè)slot來存放對(duì)象實(shí)例的引用。 - LineNumberTable屬性
使用位置:Code屬性中
用于描述java源代碼行號(hào)和字節(jié)碼行號(hào)(字節(jié)碼的偏移量)之間的對(duì)應(yīng)關(guān)系。由-g:lines控制,如果選擇不生成,堆棧中將不會(huì)顯示出錯(cuò)的行號(hào)(源代碼行號(hào))。 - LocalVariableTable屬性
使用位置:Code屬性
用以描述棧幀中局部變量表中變量與java源碼定義變量的關(guān)系。由-g:vars控制,如果選擇不生成,其他人引用這個(gè)方法時(shí),所有參數(shù)名稱都會(huì)丟失。
三、字節(jié)碼指令
一個(gè)字節(jié)長(zhǎng)度,由操作碼+操作數(shù)構(gòu)成
大部分指令都沒有支持byte、char、short等,因?yàn)榫幾g器在編譯期間擴(kuò)展為int類型數(shù)據(jù)
- 方法調(diào)用和返回指令
invokevirtual:調(diào)用對(duì)象實(shí)例方法
invokeinterface:調(diào)用接口方法
invokespecial:調(diào)用需要特殊處理的實(shí)例方法
包括實(shí)例初始化方法、私有方法和父類方法等
invokestatic:調(diào)用類方法 - 異常處理指令
- 類型轉(zhuǎn)換指令
i2b、i2c、d2f等 - 對(duì)象創(chuàng)建與訪問指令
new、newarray等
getfield、putfield、getstatic、putstatic - 同步指令
monitorenter和monitorexit