「Java 路線」| Class 文件結(jié)構(gòu)

點(diǎn)贊關(guān)注锚烦,不再迷路扩然,你的支持對(duì)我意義重大艘儒!

?? Hi,我是丑丑夫偶。本文 「Java 路線」| 導(dǎo)讀 —— 他山之石界睁,可以攻玉 已收錄,這里有 Android 進(jìn)階成長(zhǎng)路線筆記 & 博客兵拢,歡迎跟著彭丑丑一起成長(zhǎng)翻斟。(聯(lián)系方式在 GitHub)

前言

  • Class 文件Java技術(shù)體系的重要組成部分,在學(xué)習(xí)整個(gè)虛擬機(jī)的執(zhí)行引擎之前说铃,應(yīng)該清楚Class 文件的結(jié)構(gòu)访惜;
  • 這篇文章將帶你理解Class 文件的基本結(jié)構(gòu),希望能幫上忙腻扇。

延伸文章

目錄


1. 什么是 Class 文件幼苛?

  • 定義:或稱字節(jié)碼窒篱,可以看作Java 虛擬機(jī)的可執(zhí)行文件

  • 作用:對(duì)應(yīng)于一個(gè)類 / 抽象類 / 接口的定義信息

  • 意義Java 虛擬機(jī) & Class 文件共同構(gòu)成了Java無關(guān)性的基礎(chǔ)

  • 來源

      1. Java 源碼經(jīng)過Java 編譯器編譯后得到,以磁盤文件形式存在
      1. 由字節(jié)碼生成技術(shù)(如javassist / CGLib / ASM)生成,以內(nèi)存中二進(jìn)制流形式存在
# 咬文嚼字 #

雖然字節(jié)碼不一定是以 “磁盤文件” 的形式存在墙杯,但是通常在很多文獻(xiàn) & 資料中會(huì)籠統(tǒng)地將字節(jié)碼表述為Class 文件济锄,這里不必鉆牛角尖。

更多信息請(qǐng)務(wù)必閱讀:《Java | 為什么 Java 實(shí)現(xiàn)了平臺(tái)無關(guān)性》


2. Class 文件的大致結(jié)構(gòu)

  • Class 文件是一種強(qiáng)協(xié)議的緊湊型結(jié)構(gòu)(遵循《Java 虛擬機(jī)規(guī)范》)
  • Class 文件有三種數(shù)據(jù)結(jié)構(gòu):無符號(hào)數(shù)霍转、TVL、表一汽,具體如下:
  • Class 文件本質(zhì)上也是一個(gè)表避消,大致結(jié)構(gòu)如下圖:
  • 魔數(shù):固定值0xCAFEBABE,用于鑒別為合法的Class 文件
  • 版本號(hào):表示Class 文件的目標(biāo)版本號(hào)召夹,高版本的虛擬機(jī)可以向前兼容舊版本Class 文件
  • 訪問標(biāo)志:一個(gè)u2無符號(hào)數(shù)岩喷,用于表示本類 / 接口的訪問信息。其中每個(gè)標(biāo)志位的值與java.lang.reflect.Modifier中的常量一一對(duì)應(yīng):
  • 本類索引 & 父類索引 & 接口索引集:是一個(gè)索引值监憎,(共經(jīng)過 2 次索引后)指向常量池中一個(gè)utf-8編碼的 全限定名纱意,例如:java/lang/Object;

  • 字段表集合:用于描述類或接口中聲明的變量(包括類變量與成員變量)

  • 方法表集合:用于描述類或接口中聲明的方法(包括類方法與成員方法)

  • 屬性表集合:用于描述 Class 文件、字段表鲸阔、方法表中攜帶的屬性


下面偷霉,我將概括表中各個(gè)重點(diǎn)數(shù)據(jù)項(xiàng)的具體含義!

3. 常量池(const pool)

  • 常量池中的每一項(xiàng)常量都是一個(gè)表
  • 存放兩種類常量:字面量(Literal)符號(hào)引用(Symbolic References)

符號(hào)引用(Symbolic References)是一個(gè)字符串類型的字面量(存儲(chǔ)在常量池)褐筛,它的作用是唯一地標(biāo)示一個(gè)實(shí)體类少,最重要的特點(diǎn)如下:

  • 平臺(tái)無關(guān)性
    這一點(diǎn)與Java的特性是一脈相承的。符號(hào)引用與具體虛擬機(jī)實(shí)現(xiàn)內(nèi)存布局無關(guān)渔扎,需要在運(yùn)行期將符號(hào)引用轉(zhuǎn)換為直接引用(Direct Reference)硫狞,這個(gè)直接引用才是符號(hào)引用在虛擬機(jī)中的真實(shí)存在。

  • 唯一性
    無歧義地標(biāo)示一個(gè)目標(biāo)晃痴,以方法為例残吩,如果是本類中聲明的方法,不需要添加類名(如:Method func:()V)倘核;如果是其他類中聲明的方法泣侮, 需要添加類名前綴(如:Method com/Base.func:()V)。

常量池表結(jié)構(gòu)有一個(gè)共同的特點(diǎn)笤虫,就是表結(jié)構(gòu)的首元素是u1的標(biāo)志位旁瘫,代表當(dāng)前的常量類型,截止到Java 13總共有 20 種常量:

常量類型 —— 引用自《深入理解Java虛擬機(jī)》

4. 本類索引 & 父類索引 & 接口索引集

  • 本類索引肯定存在琼蚯,只有一個(gè)
  • Java是類單繼承酬凳,所以父類索引只有一個(gè)(特例:Object的父類索引為 0)
  • Java是接口多繼承,所以接口索引有零或多個(gè)

這三個(gè)索引值均指向常量池中CONSTANT_Class_info常量遭庶,而CONSTANT_Class_info常量本質(zhì)上也是一個(gè)索引值宁仔,指向CONSTANT_Utf8_info常量。經(jīng)過 2次 索引峦睡,這三個(gè)索引最終指向?qū)?yīng) 類 / 接口的全限定名

2 次索引后指向全限定名 —— 引用自《深入理解Java虛擬機(jī)》

5. 字段表(field_info)

字段表用于描述類字段與實(shí)例字段翎苫,但只包括在本類中聲明的字段权埠,既不包括父類中聲明的字段,也不包括方法內(nèi)部聲明的局部變量煎谍。要注意的是攘蔽,編譯器生成的字段是包括的,例如編譯器會(huì)為非靜態(tài)內(nèi)部類添加外部類的引用字段呐粘。字段表的基本結(jié)構(gòu)如下:

字段表的基本結(jié)構(gòu)
  • access_flags:字段的訪問標(biāo)志位
  • name_index:常量池索引满俗,最終指向字段的簡(jiǎn)單名稱,見第 8 節(jié)
  • descriptor_index:常量池索引作岖,最終指向字段的描述符唆垃,見第 8 節(jié)
  • attributes_count & attributes:字段屬性,為字段的附加信息痘儡,見第 8 節(jié)

6. 方法表(method_info)

方法表和字段表的設(shè)計(jì)是很相似的辕万。方法表用于描述類方法與實(shí)例方法,但只包括在本類中聲明的方法或者重寫的方法沉删,不包括父類或父接口中聲明的方法渐尿。需要注意的是,編譯器生成的方法是包括的矾瑰,例如類構(gòu)造器<clinit>()與實(shí)例構(gòu)造器<init>()涡戳。方法表的基本結(jié)構(gòu)如下:

方法表的基本結(jié)構(gòu)

可以看到,方法表和字段表的基本結(jié)構(gòu)是完全一致的脯倚,此處不再贅述渔彰。需要特別指出的是,方法里面的代碼在方法的Code屬性推正,方法的受檢異常聲明在Exception屬性恍涂。


7. 屬性表(attribute_info)

  • 屬性相當(dāng)于字段表或方法表的附加信息
  • 每一項(xiàng)屬性都是一個(gè)表,基本結(jié)構(gòu)如下圖所示:
屬性表的基本結(jié)構(gòu)
  • attribute_name_index:常量池索引植榕,最終指向一個(gè)屬性名再沧。Class 文件使用屬性名來區(qū)分每一種屬性,截止到Java 12尊残,總共有 29 種預(yù)定義屬性炒瘸。
  • attribute_length:不同屬性的屬性信息是不同的,因此需要一個(gè)長(zhǎng)度表表示屬性信息占用的長(zhǎng)度
  • info:屬性信息
# 你覺得呢寝衫?#

市面上你能找到的介紹虛擬機(jī)的書籍顷扩,普遍都會(huì)按順序羅列出每種屬性的信息。筆者并不是說這種方式不好慰毅,因?yàn)樽鳛闀年U述方式需要考慮到讀者可接受度 & 參考性的問題隘截。但是如果以博客的闡述方式也采用同樣地方式,豈非成為知識(shí)搬運(yùn)工?因此婶芭,我將從不同的問題域出發(fā)东臀,在每個(gè)問題域中介紹每種屬性。

Code 屬性
Exceptions 屬性

LocalVariableTable 屬性

LocalVariableTypeTable 屬性
Signature 屬性

泛型中所謂的類型擦除犀农,其實(shí)只是擦除Code 屬性中的泛型信息惰赋,在類常量池屬性中其實(shí)還保留著泛型信息,這也是在運(yùn)行時(shí)可以反射獲取泛型信息的根本依據(jù)呵哨。在這篇文章里谤逼,我們?cè)敿?xì)討論:《Java | 關(guān)于泛型能問的都在這里了(含Kotlin)》,請(qǐng)關(guān)注仇穗!


RuntimeVisibleAnnotations 屬性
RuntimeInvisibleAnnotations 屬性
RuntimeVisibleParameterAnnotations 屬性
RuntimeInvisibleParameterAnnotations 屬性

注解在編譯后擦除,如果注解的保留級(jí)別為CLASS & RUNTIME戚绕,在 Class 文件中還會(huì)生成對(duì)應(yīng)的注解屬性纹坐。在這篇文章里,我們?cè)敿?xì)討論:《Java | 這是一篇全面的注解使用攻略(含 Kotlin)》舞丛,請(qǐng)關(guān)注耘子!


InnerClasses 屬性

8. 信息描述規(guī)則

Editting...


參考資料

  • 《深入理解Java虛擬機(jī)(第3版本)》(第6章)—— 周志明 著
  • 《深入理解Android:Java虛擬機(jī) ART》(第2章) —— 鄧凡平 著
  • 《深入理解 JVM 字節(jié)碼》(第2、3球切、4章)—— 張亞 著

創(chuàng)作不易谷誓,你的「三連」是丑丑最大的動(dòng)力,我們下次見吨凑!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捍歪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鸵钝,更是在濱河造成了極大的恐慌糙臼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恩商,死亡現(xiàn)場(chǎng)離奇詭異变逃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)怠堪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門揽乱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粟矿,你說我怎么就攤上這事凰棉。” “怎么了陌粹?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵渊啰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)绘证,這世上最難降的妖魔是什么隧膏? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮嚷那,結(jié)果婚禮上胞枕,老公的妹妹穿的比我還像新娘。我一直安慰自己魏宽,他們只是感情好腐泻,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著队询,像睡著了一般派桩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚌斩,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天铆惑,我揣著相機(jī)與錄音,去河邊找鬼送膳。 笑死员魏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叠聋。 我是一名探鬼主播撕阎,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼碌补!你這毒婦竟也來了虏束?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤厦章,失蹤者是張志新(化名)和其女友劉穎魄眉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闷袒,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坑律,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了囊骤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晃择。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖也物,靈堂內(nèi)的尸體忽然破棺而出宫屠,到底是詐尸還是另有隱情,我是刑警寧澤滑蚯,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布浪蹂,位于F島的核電站抵栈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏坤次。R本人自食惡果不足惜古劲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望缰猴。 院中可真熱鬧产艾,春花似錦、人聲如沸滑绒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疑故。三九已至杠览,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纵势,已是汗流浹背踱阿。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吨悍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓蹋嵌,卻偏偏與公主長(zhǎng)得像育瓜,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子栽烂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354