《深入理解java虛擬機(jī)》-類(lèi)文件結(jié)構(gòu)

Java在剛剛誕生之初曾經(jīng)提出過(guò)一個(gè)非常著名的口號(hào):“一次編譯奴迅,導(dǎo)出執(zhí)行”,將java文件編譯為class文件,然后由JVM來(lái)處理平臺(tái)的差異性梢灭,這個(gè)特性也使其他的語(yǔ)言能夠在JVM上運(yùn)行。

Class類(lèi)文件的結(jié)構(gòu)

占用大小 字段描述 數(shù)量
4bit magic:魔數(shù)蒸其,用于標(biāo)識(shí)文件類(lèi)型敏释,對(duì)于java來(lái)說(shuō)是0xCAFEBABE 1
2bit minor_version:次版本號(hào) 1
2bit major_version:主版本號(hào) 1
2bit constant_pool_count:常量池大小,從1開(kāi)始而不是0摸袁。當(dāng)這個(gè)值為0時(shí)钥顽,表示后面沒(méi)有常量 1
不定 constant_pool#常量池 constant_pool_count-1
2bit access_flags:訪問(wèn)標(biāo)志,標(biāo)識(shí)這個(gè)class是類(lèi)還是接口靠汁、public蜂大、abstract、final等 1
2bit this_class:類(lèi)索引 #類(lèi)索引查找全限定名的過(guò)程 1
2bit super_class:父類(lèi)索引 1
2bit interfaces_count:接口計(jì)數(shù)器 1
每個(gè)2bit interfaces:接口索引集合 interfaces_count
2bit fields_count:字段的數(shù)量 1
不定 fields#字段表 fields_count
2bit methods_count:方法數(shù)量 1
不定 methods#方法表 methods_count
2bit attributes_count:屬性數(shù)量 1
不定 attrbutes#屬性表 attributes_count

常量池

主要存放兩大類(lèi)常量:

  • 字面量(Literal):類(lèi)似于java的常量
  • 符號(hào)引用(Symbolic References):屬于編譯原理方面的概念蝶怔,主要包括類(lèi)和接口的權(quán)限定名(Fully Qualified Name)县爬、字段名稱(chēng)和描述符(Descriptor)、方法名稱(chēng)和描述符添谊。
常量池中的14種常量項(xiàng)的結(jié)構(gòu)總表
使用javap命令輸出常量表

類(lèi)索引查找全限定名的過(guò)程

類(lèi)索引查找全限定名的過(guò)程

字段表

字段表集合中不會(huì)列出從超類(lèi)或者父接口中繼承而來(lái)的字段

  • access_flags字段標(biāo)識(shí)符财喳,public、private斩狱、protected耳高、static、final所踊、volatile泌枪、transient等
  • name_index:字段的簡(jiǎn)單名稱(chēng)
  • descriptor_index:字段或方法的描述符
  • attributes_count:屬性數(shù)量
  • attributes#屬性表
字段表結(jié)構(gòu)

字段訪問(wèn)標(biāo)志:

字段訪問(wèn)標(biāo)志

方法表

方法表結(jié)構(gòu)
方法訪問(wèn)標(biāo)志

屬性表

Class文件、字段表秕岛、方法表都可以攜帶自己的屬性表數(shù)據(jù)集合碌燕。與Class文件中其他的數(shù)據(jù)項(xiàng)目要求嚴(yán)格不同误证,屬性表集合的限制相對(duì)寬松。在java虛擬機(jī)規(guī)范1.7版本中定義了21項(xiàng)屬性修壕。

虛擬機(jī)規(guī)范預(yù)定義的屬性
1. Code屬性

方法體內(nèi)java代碼編譯后生成的字節(jié)碼指令存儲(chǔ)在Code屬性?xún)?nèi)愈捅,Code屬性表的結(jié)構(gòu):

Code屬性表的結(jié)構(gòu)
  • attribute_name_index:是一項(xiàng)指向CONSTANT_Utf8_info型常量的索引,常量為“Code”
  • attribute_length:屬性值的長(zhǎng)度
  • max_stack:操作數(shù)棧(Operand Stacks)深度的最大值
  • max_locals:局部變量表所需的存儲(chǔ)空間
  • code_length:字節(jié)碼長(zhǎng)度
  • code:用于存儲(chǔ)字節(jié)碼指令的一系列字節(jié)流慈鸠,每個(gè)指令就是一個(gè)1bit的單字節(jié) 一字節(jié) => 指令 => 動(dòng)作 (linux命令行蓝谨、匯編)
  • exception_table_length:異常表長(zhǎng)度
  • exception_table:異常表
    • start_pc:開(kāi)始行
    • end_pc:結(jié)束行
    • handler_pc:處理異常行
    • catch_type:當(dāng)catch_type類(lèi)型或其子類(lèi)型的異常發(fā)生時(shí),轉(zhuǎn)到handler_pc
異常表結(jié)構(gòu)
2. Exceptions屬性

Exceptions屬性的作用是列舉處方法中可能拋出的受檢異常(Checked Exceptions)

Exceptions屬性結(jié)構(gòu)
  • number_of_exceptions:受檢異常數(shù)
  • exception_index_table:是一個(gè)指向CONSTANT_Class_info型常量的索引青团,代表異常類(lèi)型
3. LineNumberTable屬性

LineNumberTable屬性用于描述java源碼行號(hào)與字節(jié)碼號(hào)碼之間的對(duì)應(yīng)關(guān)系譬巫。它不是運(yùn)行時(shí)必需的屬性,可以不生成督笆。不生成時(shí)芦昔,拋出異常堆棧中不會(huì)顯示出錯(cuò)的行號(hào)

LineNumberTable屬性結(jié)構(gòu)

line_number_table是一個(gè)數(shù)量為line_number_table_length,類(lèi)型為line_number_info的集合娃肿,line_number_info表包括了start_pc和line_number兩個(gè)2bit的數(shù)據(jù)項(xiàng)烟零,前者是字節(jié)碼行號(hào),后者是java源碼行號(hào)

4. LocalVariableTable屬性

LocalVariableTable屬性用于描述幀棧中局部變量表中的變量與java源碼中定義的變量之間的關(guān)系咸作,也不是必需的锨阿,可以不生成。不生成時(shí)记罚,其他人引用這個(gè)方法墅诡,所有的參數(shù)名稱(chēng)都將會(huì)丟失

LocalVariableTable屬性結(jié)構(gòu)

local_variable_info項(xiàng)目代表了一個(gè)棧幀與源碼中的局部變量的關(guān)聯(lián)

Local_variable_info項(xiàng)目結(jié)構(gòu)
  • start_pc:這個(gè)局部變量的生命周期開(kāi)始的字節(jié)碼偏移量
  • length:作用范圍覆蓋的長(zhǎng)度
  • name_index:局部變量名稱(chēng)
  • descriptor_index:局部變量的描述符
  • index:局部變量在棧幀局部變量表中Slot的位置
5. SourceFile屬性

SourceFile屬性用于記錄生成這個(gè)Class文件的源碼文件名稱(chēng),也不是必需的桐智,可以不生成末早。不生成時(shí),拋出異常堆棧中將不會(huì)顯示出錯(cuò)代碼所屬的文件名

SourceFile屬性結(jié)構(gòu)
6. ConstantValue屬性

ConstantValue屬性的作用是通知虛擬機(jī)自動(dòng)為靜態(tài)變量賦值

7. InnerClasses屬性

InnerClasses屬性用于記錄內(nèi)部類(lèi)與宿主類(lèi)之間的關(guān)聯(lián)

8. Deprecated及Synthetic屬性

這兩個(gè)屬性都是布爾屬性说庭。Deprecated代表這個(gè)類(lèi)然磷、字段或方法已經(jīng)過(guò)時(shí),不再推薦使用刊驴。Synthetic代表此字段或者方法不是由java源碼直接產(chǎn)生的姿搜,而是由編譯器自行添加的。

9. StackMapTable屬性

StackMapTable屬性會(huì)在虛擬機(jī)類(lèi)加載的字節(jié)碼驗(yàn)證階段被新類(lèi)型檢查驗(yàn)證器(Type Checker)使用目的在于代替以前比較消耗性能的基于數(shù)據(jù)流分析的類(lèi)型推導(dǎo)驗(yàn)證器

10. Signature屬性

Signature屬性用于記錄泛型簽名信息

11. BootstrapMethods屬性

BootstrapMethods屬性用于保存invokedynamic指令引用的引導(dǎo)方法限定符

bootstrap_methods屬性的結(jié)構(gòu)

bootstrap_method屬性結(jié)構(gòu)

bootstrap_method屬性的結(jié)構(gòu)
  • bootstrap_method_ref:必須是一個(gè)對(duì)常量池中CONSTANT_MethodHandle_info結(jié)構(gòu)的有效索引
  • num_bootstrap_arguments:bootstrap_arguments的數(shù)量
  • bootstrap_arguments[]:必須是一個(gè)對(duì)常量池的有效索引

字節(jié)碼指令簡(jiǎn)介

java虛擬機(jī)的指令由一個(gè)字節(jié)長(zhǎng)度的捆憎、代表著某種特定操作含義的數(shù)字(操作碼Opcode)以及跟隨其后的0至多個(gè)代表此操作所需參數(shù)(操作數(shù)Operands)而構(gòu)成舅柜。由于java虛擬機(jī)采用面向操作數(shù)棧而不是寄存器的架構(gòu),所以大多數(shù)的指令都不包含操作數(shù)躲惰,只有一個(gè)操作碼

字節(jié)碼與數(shù)據(jù)類(lèi)型

  • l代表long
  • s代表short
  • b代表byte
  • c代表char
  • f代表float
  • d代表double
  • a代表reference

在java虛擬機(jī)中指令集不是完全獨(dú)立的(Not Orthogonal)致份,即不是每種數(shù)據(jù)類(lèi)型和每一種操作都有對(duì)應(yīng)的指令,有一些單獨(dú)的指令可以在必要的時(shí)候用在將一些不支持的類(lèi)型轉(zhuǎn)換為可被支持的類(lèi)型

加載和存儲(chǔ)命令

加載和存儲(chǔ)指令用于將數(shù)據(jù)在幀棧中的局部變量表和操作數(shù)棧之間來(lái)回傳遞

  • 將一個(gè)局部變量加載到操作棧:iload础拨、iload_<\n>氮块、lload绍载、lload_<\n>、fload滔蝉、fload_<\n>击儡、dload、dload_<\n>锰提、aload曙痘、aload_<\n>
  • 將一個(gè)數(shù)值從操作數(shù)棧存儲(chǔ)到局部變量表:istore芳悲、istore_<\n>立肘、lstore、lstore_<\n>名扛、fstore谅年、fstore_<\n>、dstore肮韧、dstore_<\n>融蹂、astore、astore_<\n>
  • 將一個(gè)參數(shù)加載到操作數(shù)棧:bipush弄企、sipush超燃、ldc、ldc_w拘领、ldc2_w意乓、aconst_null、iconst_m1约素、iconst_<\i>届良、lconst_<l>、fconst_<\f>圣猎、dconst_<\d>
  • 擴(kuò)充局部變量表的訪問(wèn)索引的指令:wide

上面帶尖括號(hào)的指令實(shí)際上是代表的一組指令士葫,如iload_0、iload_1送悔、iload_2和iload_3慢显。這些指令把操作數(shù)隱含在名稱(chēng)內(nèi),不需要進(jìn)行取操作數(shù)的動(dòng)作

運(yùn)算指令

運(yùn)算或算術(shù)指令用于對(duì)兩個(gè)操作數(shù)棧上的值進(jìn)行某種特定運(yùn)算欠啤,并把結(jié)果重新存入到操作棧頂鳍怨,可分為整型數(shù)據(jù)和浮點(diǎn)型數(shù)據(jù)指令。byte跪妥、short鞋喇、char和boolean類(lèi)型的算術(shù)指令使用int類(lèi)型的指令代替

  • 加法指令:iadd、ladd眉撵、fadd侦香、dadd
  • 減法指令:isub落塑、lsub、fsub罐韩、dsub
  • 乘法指令:imul憾赁、lmul、fmul散吵、dmul
  • 除法指令:idiv龙考、ldiv、fdiv矾睦、ddiv
  • 求余指令:irem晦款、lrem、frem枚冗、drem
  • 取反指令:ineg缓溅、lneg、fneg赁温、dneg
  • 位移指令:ishl坛怪、ishr、iushr股囊、lshl袜匿、lshr、lushr
  • 或指令:ior稚疹、lor
  • 與指令:iand居灯、land
  • 異或指令:ixor、lxor
  • 局部變量自增指令:iinc
  • 比較指令:dcmpg贫堰、dcmpl穆壕、fcmpg、fcmpl其屏、lcmp

類(lèi)型轉(zhuǎn)換指令

類(lèi)型轉(zhuǎn)換指令可以將兩種不同的數(shù)值類(lèi)型進(jìn)行相互轉(zhuǎn)換喇勋,一般用于實(shí)現(xiàn)用戶代碼中的顯示類(lèi)型轉(zhuǎn)換操作,或者處理字節(jié)碼指令集中數(shù)據(jù)類(lèi)型相關(guān)指令無(wú)法與數(shù)據(jù)類(lèi)型一一對(duì)應(yīng)的問(wèn)題

  • 寬化類(lèi)型轉(zhuǎn)換(Widening Numeric Conversions偎行,即小范圍類(lèi)型向大范圍類(lèi)型的安全轉(zhuǎn)換):轉(zhuǎn)換時(shí)無(wú)需顯式的轉(zhuǎn)換指令
  • 窄化類(lèi)型轉(zhuǎn)換(Narrowing Numeric Conversions):必需顯式地使用轉(zhuǎn)換指令川背。i2b、i2c蛤袒、i2s熄云、l2i、f2i妙真、f2l缴允、d2i、d2l珍德、d2f练般,轉(zhuǎn)換時(shí)可能導(dǎo)致數(shù)值的進(jìn)度丟失

對(duì)象創(chuàng)建與訪問(wèn)指令

  • 創(chuàng)建類(lèi)實(shí)例的指令:new
  • 創(chuàng)建數(shù)組的指令:newarray矗漾、anewarray、multianewarray
  • 訪問(wèn)類(lèi)字段和實(shí)例字段的實(shí)例:getfield薄料、putfield敞贡、getstatic、putstatic
  • 把一個(gè)數(shù)組元素加載到操作數(shù)棧的指令:baload摄职、caload誊役、saload、iaload谷市、laload蛔垢、faload、daload歌懒、aaload
  • 將一個(gè)操作數(shù)棧的值存儲(chǔ)到數(shù)組元素中的指令:bastore啦桌、castore溯壶、sastore及皂、iastore、fasotre且改、dastore验烧、aastore
  • 取數(shù)組長(zhǎng)度的指令:arraylength
  • 檢查類(lèi)實(shí)例類(lèi)型的指令:instanceof、checkcast

操作數(shù)棧管理指令

  • 將操作數(shù)棧的棧頂一個(gè)或兩個(gè)元素出棧:pop又跛、pop2
  • 復(fù)制棧頂一個(gè)或兩個(gè)數(shù)值并將復(fù)制值或雙份的復(fù)制值重新壓入棧頂:dup碍拆、dup2、dup_x1慨蓝、dup2_x1感混、dup_x2、dup2_x2
  • 將棧最頂端的兩個(gè)數(shù)值互換:swap

控制轉(zhuǎn)移指令

  • 條件分支:fieq礼烈、iflt弧满、ifle、ifne此熬、ifgt庭呜、ifge、ifnull犀忱、ifnonnull募谎、if_icmpeq、if_icmpne阴汇、if_icmplt数冬、if_icmpgt、if_icmpge搀庶、if_acmpeq拐纱、if_acmpne
  • 復(fù)合條件分支:tableswitch疯淫、lookupswitch
  • 無(wú)條件分支:goto、goto_w戳玫、jsr熙掺、jsr_w、ret

方法調(diào)用和返回指令

  • invokevirtual指令:用于調(diào)用對(duì)象的實(shí)例方法咕宿,根據(jù)對(duì)象的實(shí)際類(lèi)型進(jìn)行分派
  • invokeinterface指令:用于調(diào)用接口方法
  • invokespecial指令:用于調(diào)用一些需要特殊處理的實(shí)例方法币绩,包括實(shí)例初始化方法、私有方法和父類(lèi)方法
  • invokestatic指令:用于調(diào)用類(lèi)方法(static方法)
  • invokedynamic指令:用于在運(yùn)行時(shí)動(dòng)態(tài)解析出調(diào)用點(diǎn)限定符所引用的方法府阀,并執(zhí)行該方法

異常處理指令

在java程序中缆镣,顯式拋出異常的操作都由athrow指令來(lái)實(shí)現(xiàn)。而在java虛擬機(jī)中试浙,處理異常不是由字節(jié)碼指令來(lái)實(shí)現(xiàn)的董瞻,而是采用異常表來(lái)完成的

同步指令

java虛擬機(jī)可以支持方法級(jí)的同步和方法內(nèi)部一段指令序列的同步,這兩種同步結(jié)構(gòu)都是使用管程(Monitor)來(lái)支持的田巴。方法級(jí)的同步是隱式的钠糊,利用方法表結(jié)構(gòu)中的ACC_SYNCHRONIZED訪問(wèn)標(biāo)志得知。指令序列的同步是由monitorenter和monitorexit兩條指令支持壹哺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抄伍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子管宵,更是在濱河造成了極大的恐慌截珍,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件箩朴,死亡現(xiàn)場(chǎng)離奇詭異岗喉,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)炸庞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)钱床,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人燕雁,你說(shuō)我怎么就攤上這事诞丽。” “怎么了拐格?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵僧免,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我捏浊,道長(zhǎng)懂衩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮浊洞,結(jié)果婚禮上牵敷,老公的妹妹穿的比我還像新娘。我一直安慰自己法希,他們只是感情好枷餐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著苫亦,像睡著了一般毛肋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上屋剑,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天润匙,我揣著相機(jī)與錄音,去河邊找鬼唉匾。 笑死孕讳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的巍膘。 我是一名探鬼主播厂财,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼典徘!你這毒婦竟也來(lái)了蟀苛?” 一聲冷哼從身側(cè)響起益咬,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤逮诲,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后幽告,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體梅鹦,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年冗锁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了齐唆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡冻河,死狀恐怖箍邮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情叨叙,我是刑警寧澤锭弊,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站擂错,受9級(jí)特大地震影響味滞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一剑鞍、第九天 我趴在偏房一處隱蔽的房頂上張望昨凡。 院中可真熱鬧,春花似錦蚁署、人聲如沸便脊。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)就轧。三九已至,卻和暖如春田度,著一層夾襖步出監(jiān)牢的瞬間妒御,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工镇饺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乎莉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓奸笤,卻偏偏與公主長(zhǎng)得像惋啃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子监右,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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