從.java到.class

一、class 類文件

class文件是一組以8位字節(jié)為基礎(chǔ)的二進(jìn)制流,中間沒有任何分隔符,所以數(shù)據(jù)的含義和順序都被嚴(yán)格限定。
class 文件使用兩種數(shù)據(jù)類型保存數(shù)據(jù):

  1. 無符號(hào)數(shù)(有符號(hào)數(shù)有正負(fù)之分)
  2. 表(由無符號(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):

  1. java中,overload除與原方法同名之外,還要求與原方法特征簽名不同,特征簽名就是一個(gè)方法中各個(gè)參數(shù)在常量池中的字段符號(hào)引用的集合,而返回值不包含在特征簽名中
  2. this關(guān)鍵字
    編譯時(shí)把this關(guān)鍵字的訪問,轉(zhuǎn)換為普通方法參數(shù)的訪問,調(diào)用時(shí)自動(dòng)傳入當(dāng)前實(shí)例。局部變量表中也會(huì)預(yù)留第一個(gè)slot來存放對(duì)象實(shí)例的引用。
  3. LineNumberTable屬性
    使用位置:Code屬性中
    用于描述java源代碼行號(hào)和字節(jié)碼行號(hào)(字節(jié)碼的偏移量)之間的對(duì)應(yīng)關(guān)系。由-g:lines控制,如果選擇不生成,堆棧中將不會(huì)顯示出錯(cuò)的行號(hào)(源代碼行號(hào))。
  4. 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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容