Technical--Documentation
共享技術(shù)文檔
項(xiàng)目簡介
為為日常工作和學(xué)習(xí)的總結(jié)。
技術(shù)文檔主站簡介
主站文檔是我在前人的腳步上對研發(fā)的學(xué)習(xí)和總結(jié)紀(jì)錄厘肮,在以后的日子里良漱,我會將自己研發(fā)工作中所可能遇見問題和心得在這里紀(jì)錄下來舞虱,公開的分享。世界的存在很美好母市,開源的存在很精彩矾兜。從今天起,我便借助開源的力量患久,向改變?nèi)祟惖纳罘绞竭@條路邁進(jìn)椅寺。
點(diǎn)擊這里直接進(jìn)入為為技術(shù)文檔主站,或者訪問 https://weiwei02.github.io/Technical--Documentation/
與文檔配套的 Technical--Documentation項(xiàng)目的地址是 https://github.com/weiwei02/Technical--Documentation
*.class文件介紹
一般來講.class文件是.java文件在編譯器編譯后生成的jvm能夠運(yùn)行的文件蒋失,*.class文件又常被稱為字節(jié)碼文件返帕。java在創(chuàng)始之初,就提倡“一次編寫篙挽,處處運(yùn)行的概念”荆萤,在當(dāng)今編程圈中這個概念早已不是什么特例。java通過將開發(fā)人員所編寫的java代碼編譯成class文件铣卡,然后由jvm虛擬機(jī)在執(zhí)行時將不分平臺的class文件中的字節(jié)碼链韭,再翻譯成機(jī)器碼,交給硬件執(zhí)行煮落。java就是靠jvm虛擬機(jī)的這個設(shè)計(jì)來實(shí)現(xiàn)與平臺無關(guān)的特性的敞峭。class文件不但與硬件平臺和操作系統(tǒng)無關(guān),也和具體的編程語言無關(guān)蝉仇,就目前來說旋讹,如函數(shù)式編程語言scala與Groovy都可以通過自己的編譯器將源代碼編譯成class文件殖蚕,在jvm上運(yùn)行。
綜合來講骗村,class文件有以下兩點(diǎn)特性:
- 與硬件和操作系統(tǒng)平臺無關(guān)
- 與源碼所使用的編程語言無關(guān)
class類文件的結(jié)構(gòu)
每一個class文件都唯一對應(yīng)著java類或接口枚舉等定義信息嫌褪,但類不一定都定義在class文件中,類可能是由類加載器動態(tài)生成的胚股。
class文件所以被稱之為字節(jié)碼據(jù)我猜測可能是因?yàn)閏lass文件以8位(1字節(jié))為單位進(jìn)行存儲的二進(jìn)制信息笼痛。字節(jié)碼中各個數(shù)據(jù)項(xiàng)目嚴(yán)格按照順序緊湊的排列,中間沒有任何分割符琅拌。在需要存儲整型或浮點(diǎn)型這些大于8位的數(shù)據(jù)項(xiàng)目時缨伊,則會使用Big-Endian的字節(jié)序進(jìn)行存儲进宝,將最高位字節(jié)放在地址最低位刻坊,最低位字節(jié)放在地址最高位。
class文件格式采用表來存儲數(shù)據(jù)党晋,表中有無符號數(shù)和表兩種數(shù)據(jù)類型谭胚。對于這兩種數(shù)據(jù)類型說明如下:
- 無符號數(shù): 無符號數(shù)是基本的數(shù)據(jù)類型,可以用來表示數(shù)字未玻、索引引用灾而、數(shù)量值或者按照UTF-8編碼構(gòu)成的字符串。如u1,u2,u4,u8分別代表1,2,4,8個字節(jié)字節(jié)的無符號數(shù)扳剿。
- 表: 表是由多個無符號數(shù)或者其它表作為數(shù)據(jù)項(xiàng)所組成的復(fù)合數(shù)據(jù)結(jié)構(gòu)旁趟,表用于描述層次關(guān)系和復(fù)合的數(shù)據(jù)結(jié)構(gòu),整個class文件就是一張表庇绽。通常表以 _info 結(jié)尾锡搜。如表1就是一個class的表示例。
類型 | 名稱 | 數(shù)量 |
---|---|---|
u4 | magic | 1 |
u2 | minor_version | 1 |
u2 | major_version | 1 |
u2 | constant_pool_count | 1 |
cp_info | constant_pool | constant_pool_count - 1 |
u2 | asscess_flags | 1 |
u2 | this_class | 1 |
u2 | super_class | 1 |
u2 | interfaces_count | 1 |
u2 | interfaces | interfaces_count |
u2 | fields_count | 1 |
field_info | fields | fields_count |
u2 | methods_count | 1 |
method_info | methods | method_count |
u2 | attributes_count | 1 |
attribute_info | attributes | attributes_count |
表 1 class文件格式
class文件的順序和格式必須嚴(yán)格實(shí)現(xiàn)按照上述規(guī)則瞧掺,否則jvm將不能識別執(zhí)行耕餐。
Magic Number 魔數(shù)
魔數(shù)是一個和文件后綴名相似的用于文件格式識別的約定,一般規(guī)定文件內(nèi)容開頭的前幾個字節(jié)為文件的魔數(shù)辟狈。不同于文件后綴名很容易被用戶以重命名的方式進(jìn)行更改肠缔,文件的魔數(shù)作為識別手段可以更安全的確定文件的可用性。
class文件使用前4個字節(jié)作為魔數(shù)上陕,來確定.class文件是否是一個能夠被虛擬機(jī)識別的文件桩砰,其值是 0xCAFFEBABE 拓春。
版本
class文件的第5-6個字節(jié)代表的可執(zhí)行該class文件的目標(biāo)虛擬機(jī)的最低次版本號(Minor Version)释簿,第7-8個字節(jié)是主版本號(Major Version)。java虛擬機(jī)可以運(yùn)行比當(dāng)前虛擬機(jī)版本號低的class文件硼莽,拒絕運(yùn)行版本號不合法庶溶,或比自己版本高的class文件煮纵。JDK1.1的版本號是45,之后的每個大版本發(fā)布都把主版本號加1,如JDK1.2主版本號是46,JDK8的版本號是52撑碴。
JDK在編譯java文件是可以通過 javac -target 1.6 ...
命令來指定編譯后的class文件可以在1.6的虛擬機(jī)版本上運(yùn)行宵睦。
常量池
常量池是class文件中第一個表類型的數(shù)據(jù)項(xiàng)目,常量池是class文件中的資源倉庫瞬痘,是class文件結(jié)構(gòu)中與其它項(xiàng)目關(guān)聯(lián)最多的數(shù)據(jù)類型,也是占用class文件空間最大的數(shù)據(jù)項(xiàng)目之一。
class文件里緊隨版本之后的數(shù)據(jù)項(xiàng)是常量池贞让,由于常量池的數(shù)量是不固定的,所以在常量池的數(shù)據(jù)項(xiàng)之前放置的有一個u2類型的數(shù)據(jù)柳譬,代表常量池的大小喳张。常量池大小的初始值是1,如常量池的大小的數(shù)據(jù)如果顯示的是10美澳,就代表該class文件中有9個常量销部。
常量池中主要存放兩大類常量:Literal(字面常量)、Symbolic Reference(符號引用常量)制跟。字面常量類似于java中常量的概念舅桩,如文本字符串、final關(guān)鍵字所聲明的常量等凫岖。而符號引用常量則是編譯中的概念江咳,主要包括以下三種類型的常量。
- 符號常量
+ 類和接口的全限定名(Fully Qualified Name)
+ 字段名稱和描述符(Descriptor)
+ 方法的名稱和描述符
class文件中不會保存各個方法或字段在內(nèi)存中的布局信息哥放,而是在虛擬機(jī)加載class文件時進(jìn)行動態(tài)的連接歼指。虛擬機(jī)在運(yùn)行class文件時從常量池中獲取對應(yīng)的符號引用,再在創(chuàng)建類或者運(yùn)行時解析連接到具體的內(nèi)存地址當(dāng)中甥雕。
常量池中的每一個常量都是一個表踩身,在JDK8中有14種表結(jié)構(gòu)的常量表。如表 2 所示社露。
類型 | 標(biāo)識 | 描述 |
---|---|---|
CONSTANT_utf8_info | 1 | UTF-8編碼的字符串 |
CONSTANT_Integer_info | 3 | 整形字面量 |
CONSTANT_Float_info | 4 | 浮點(diǎn)型字面量 |
CONSTANT_Long_info | 5 | 長整型字面量 |
CONSTANT_Double_info | 6 | 雙精度浮點(diǎn)型字面量 |
CONSTANT_Class_info | 7 | 類或接口的符號引用 |
CONSTANT_String_info | 8 | 字符串類型字面量 |
CONSTANT_Fieldref_info | 9 | 字段的符號引用 |
CONSTANT_Methodref_info | 10 | 類中方法的符號引用 |
CONSTANT_InterfaceMethodref_info | 11 | 接口中方法的符號引用 |
CONSTANT_NameAndType_info | 12 | 字段或方法的符號引用 |
CONSTANT_MothodType_info | 16 | 標(biāo)志方法類型 |
CONSTANT_MethodHandle_info | 15 | 表示方法句柄 |
CONSTANT_InvokeDynamic_info | 18 | 表示一個動態(tài)方法調(diào)用點(diǎn) |
表 2 常量池?cái)?shù)據(jù)項(xiàng)目類型表
這14種常量結(jié)構(gòu)表開始的第一個字節(jié)都是一個u1類型的標(biāo)識位挟阻,其值就是表2中每項(xiàng)常量表類型所對應(yīng)的標(biāo)識列的值,代表當(dāng)前常量屬于哪種常量類型峭弟。這14種常量類型各自有自己不同的表結(jié)構(gòu)附鸽,詳情如表 3 所示。
常量 | 項(xiàng)目 | 類型 | 描述 |
---|---|---|---|
CONSTANT_Utf8_info | tag | u1 | 值為1 |
length | u2 | UTF-8編碼的字符串占用的字節(jié)數(shù) | |
bytes | u1 | utf-8編碼的字符串 | |
CONSTANT_Integer_info | tag | u1 | 值為3 |
bytes | u4 | 按照Big-Endian存儲的int值 | |
CONSTANT_Float_info | tag | u1 | 4 |
bytes | u4 | 按照Big-Endian存儲的float值 | |
CONSTANT_Long_info | tag | u1 | 5 |
bytes | u8 | 按照Big-Endian存儲的long值 | |
CONSTANT_Double_info | tag | u1 | 6 |
bytes | u8 | 按照Big-Endian存儲的long值double值 | |
CONSTANT_Class_info | tag | u1 | 7 |
index | u2 | 指向全限定名常量項(xiàng)的索引 | |
CONSTANT_String_info | tag | u1 | 8 |
index | u2 | 指向字符串常量的索引 | |
CONSTANT_Fieldref_info | tag | u1 | 9 |
index | u2 | 指向聲明字段的類或接口描述符CONSTANT_Class_info的索引值 | |
index | u2 | 指向CONSTANT_NameAndType_info的索引值 | |
CONSTANT_Methodref_info | tag | u1 | 10 |
index | u2 | 指向聲明方法的類描述符CONSTANT_Class_info的索引值 | |
index | u2 | 指向CONSTANT_NameAndType_info的索引值 | |
CONSTANT_InterfaceMethodref_info | tag | u1 | 11 |
index | u2 | 指向聲明方法的接口描述符CONSTANT_Class_info的索引值 | |
index | u2 | 指向CONSTANT_NameAndType_info的索引值 | |
CONSTANT_NameAndType_info | tag | u1 | 12 |
index | u2 | 指向該字段或方法名稱常量的索引值 | |
index | u2 | 指向該字段或方法描述符常量的索引值 | |
CONSTANT_MethodHandle_info | tag | u1 | 15 |
reference_kind | u1 | 值必須1~9瞒瘸,它決定了方法句柄的的類型坷备。方法句柄類型的值表示方法句柄的字節(jié)碼行為 | |
reference_index | u2 | 對常量池的有效索引 | |
CONSTANT_MethodType_info | tag | u1 | 16 |
description_index | u2 | 對常量池中方法描述符的有效索引常量池在該處的索引必須是CONSTANT_Utf8_info的結(jié)構(gòu),表示方法的描述符情臭。 | |
CONSTANT_InvokeDynamic_info | tag | u1 | 18 |
bootstap_method_attr_index | u2 | 對當(dāng)前class文件中引導(dǎo)方法表的bootstap_methods[]數(shù)組的有效索引 | |
name_and_type_index | u2 | 對當(dāng)前常量池的有效索引省撑,常量池在此處必須是CONSTANT_NameAndType_info結(jié)構(gòu)赌蔑,表示方法名和方法描述。 |
表 3 常量池中14中常量的結(jié)構(gòu)總表
在表 3 中可以看到class文件所支持的所有的常量的結(jié)構(gòu)信息竟秫,另外由于class中的類名娃惯、方法、字段都要用CONSTANT_Utf8_info型的常量來描述名稱肥败,所以CONSTANT_Utf8_info的最大長度也是java中類名趾浅、方法名或字段的最大長度65535,如果超出這個最大長度馒稍,便會無法編譯潮孽。
訪問權(quán)限標(biāo)識
引用
在寫作本文的過程中引用了以下資料,為為在此深深謝過以下資料的作者筷黔。
- 《The Java Virtual Machine Specification》
- 《深入理解Java虛擬機(jī):JVM高級特性與最佳實(shí)踐/周志明著.——2版.——北京:機(jī)械工業(yè)出版社往史,2013.6》
關(guān)于
本項(xiàng)目和文檔中所用的內(nèi)容僅供學(xué)習(xí)和研究之用,轉(zhuǎn)載或引用時請指明出處佛舱。如果你對文檔有疑問或問題椎例,請?jiān)陧?xiàng)目中給我留言或發(fā)email到 weiwei02@vip.qq.com
from weiwei.wang 20170625