對(duì).java文件進(jìn)行編譯后扛吞,就生成了.class文件米辐。
那么class文件是什么樣的呢颂鸿?
在Java最初設(shè)計(jì)的時(shí)候吗冤,設(shè)計(jì)者們就卡率過(guò)并實(shí)現(xiàn)了讓其他語(yǔ)言運(yùn)行在java虛擬機(jī)上的可能性便贵。
所以问顷,刻意將Java的規(guī)范拆分成了Java語(yǔ)言規(guī)范和jav虛擬機(jī)規(guī)范昂秃。
實(shí)現(xiàn)了java虛擬機(jī)的語(yǔ)言無(wú)關(guān)性。
其實(shí)就是最后統(tǒng)一成存儲(chǔ)為字節(jié)碼的Class文件择诈,
使用JRuby等其他語(yǔ)言可以編譯成Class文件械蹋,使用java也可以編譯成Class文件。
有一些java語(yǔ)言本身無(wú)法有效支持的語(yǔ)言特性羞芍,并不代表字節(jié)碼本身不支持哗戈。
類(lèi)文件結(jié)構(gòu)
Class文件就是個(gè)很被規(guī)范的二進(jìn)制文件。
其實(shí)就是要規(guī)范荷科,那個(gè)class文件的解釋器才能認(rèn)得它唯咬,
而且要夠精煉,才能高效運(yùn)行畏浆。
和C語(yǔ)言編譯成匯編一樣的道理胆胰。就是一個(gè)規(guī)范的文件而已。
做一下規(guī)定:
class的文件格式:
* magic:魔數(shù)刻获,用于確定這個(gè)文件是否為一個(gè)能被虛擬機(jī)接收的Class文件蜀涨,一種標(biāo)識(shí)。
Class文件的魔數(shù):0xCAFEBABE
* Minor_version,Major_version:java的版本號(hào)蝎毡,用于該class文件表示可以支持的java語(yǔ)言版本厚柳。
* Constant_pool:常量池
* Access_flags:訪問(wèn)標(biāo)識(shí),用于識(shí)別一些類(lèi)或是接口層次的訪問(wèn)信息
占用兩個(gè)字節(jié)沐兵,所以應(yīng)該有16個(gè)標(biāo)志位别垮,標(biāo)志位為1表示true,為0表示false扎谎。
目前只有其中8個(gè)標(biāo)識(shí)為被使用碳想,沒(méi)有使用一律為0烧董;
如:0x0021則后面八個(gè)二進(jìn)制為:00100001,
所以倒數(shù)第1位為public,倒數(shù)第6位為Super胧奔。這個(gè)兩個(gè)為true逊移。
*This_class:類(lèi)索引,用于其額定這個(gè)類(lèi)的 權(quán)限定名
*super_class:父類(lèi)索引葡盗,用于確定這個(gè)類(lèi)的父類(lèi)的權(quán)限定名螟左。
*interfaces:接口索引集合,用于描述這個(gè)類(lèi)實(shí)現(xiàn)了哪些接口
*fields:字段表集合
*methods:方法表集合
*attributes:屬性表集合
Constant_pool:常量池
常量池是Class文件中與其他項(xiàng)目關(guān)聯(lián)最多的數(shù)據(jù)類(lèi)型觅够,也是占用class文件空間最大的數(shù)據(jù)項(xiàng)目之一。 常量池中主要存放:字面量(Literal)巷嚣、符號(hào)引用(Symbolic References)
```
如上圖所示喘先,常量池中存放著各種了類(lèi)型的數(shù)據(jù),共count個(gè)廷粒,如果count=0窘拯,就后面什么都沒(méi)有了。 每個(gè)數(shù)據(jù)都有一個(gè)字節(jié)的標(biāo)志tag來(lái)識(shí)別數(shù)據(jù)的類(lèi)型坝茎,從而獲得數(shù)據(jù)結(jié)構(gòu)涤姊,以解析。
前面提到的
類(lèi)索引和父類(lèi)索引嗤放,他們就是指向了一個(gè) CONSTANT_Class_info 的類(lèi)描述符常量```
attributes:屬性表集合
先說(shuō)attributes ,因?yàn)楹竺娴臅?huì)依賴這個(gè)
其中attribute_name_index中放置了一個(gè)引用常量池中的
索引
思喊,這個(gè)
索引
會(huì)指向一個(gè)常量池中的CONSTANT_Utf8_info型的常量,這個(gè)字符常量就會(huì)指出attribute的類(lèi)型次酌。
##虛擬機(jī)規(guī)范預(yù)定義的屬性
屬性名稱 | 使用位置 | 含義 |
---|---|---|
Code | 方法表 | Java代碼編譯成的字節(jié)碼指令 |
Constant | 字段表 | final關(guān)鍵字定義的常量值 |
Deprecated | 類(lèi)恨课、放發(fā)表、字段表 | 被聲明為deprecated的方法和字段 |
Exception | 方法表 | 方法拋出的異常 |
InnerClasses | 類(lèi)文件 | 內(nèi)部類(lèi)列表 |
LineNumberTable | Code屬性 | Java源碼的行號(hào)與字節(jié)碼指令對(duì)應(yīng)關(guān)系 |
LocalVarialeTable | Code屬性 | 方法的局部變量描述 |
SourceFile | 類(lèi)文件 | 源文件名稱 |
Synthetic | 類(lèi)岳服、方法表剂公、字段表 | 標(biāo)識(shí)方法或字段為編譯器自動(dòng)生成的 |
Java虛擬機(jī)運(yùn)行是會(huì)忽略它不認(rèn)識(shí)的屬性。
而每個(gè)屬性吊宋,都有自己的格式纲辽,比如
- ConstantValue
類(lèi)型 | 名稱 | 數(shù)量 |
---|---|---|
2個(gè)字節(jié) | attribute_name_index | 1 |
4個(gè)字節(jié) | attribute_length | 1 |
2個(gè)字節(jié) | constantvalue_index | 1 |
這里ConstantValue的attribute_length
比較特殊,必須是2璃搜,因?yàn)楹竺娴?code>constantvalue_index是2個(gè)字節(jié),但其實(shí)也不特殊拖吼。
其他的也有自己相應(yīng)的格式。
interface:接口集合
一堆接口的索引
fields:字段表集合
用于描述接口或類(lèi)中聲明的變量腺劣。
字段包括了{(lán)類(lèi)級(jí)變量
,實(shí)例級(jí)變量
}绿贞,但不包含方法內(nèi)部聲明的變量
Access_flags:字段訪問(wèn)標(biāo)志
name_index:字段名索引
descriptor_index:字段數(shù)據(jù)類(lèi)型索引
屬性中則是字段額外的信息,比如:
final static int m =123;
那么會(huì)有一項(xiàng)名為ConstantValue的屬性橘原,其值指向常量123
描述符標(biāo)識(shí)字符含義
|標(biāo)識(shí)字符|含義|
|:-:|:-:|
|B|基本類(lèi)型 byte|
|C|基本類(lèi)型 char|
|D|基本類(lèi)型 double|
|F|基本類(lèi)型 float|
|I|基本類(lèi)型 int|
|J|基本類(lèi)型 long|
|S|基本類(lèi)型 short|
|Z|基本類(lèi)型 boolean|
|V|特殊類(lèi)型 void|
|L|對(duì)象類(lèi)型,如Ljava/lang/Object |
* ```而
對(duì)于同樣數(shù)組類(lèi)型籍铁,每一維度將使用前置的 "[" 字符來(lái)描述
舉例子 如
"java.lang.String[][]" => "[[Ljava/lang/String"
"int[]"=>"[I"
methods:方法表集合
用于描述接口或類(lèi)中聲明的變量涡上。
字段包括了{(lán)類(lèi)級(jí)變量
,實(shí)例級(jí)變量
},但不包含方法內(nèi)部聲明的變量
- ``
Access_flags:方法訪問(wèn)標(biāo)志
name_index:方法名索引
descriptor_index:方法描述符
按照先參數(shù)列表拒名,后返回值的順序描述吩愧,參數(shù)列表按參數(shù)的嚴(yán)格順序放在一組小括號(hào)“()”之內(nèi)。
例子:
void inc() 描述符:()V
java.lang.String toString() =>()Ljava/lang/String
int indexOf(char[] source,int sourceOffset,char[] target,int targetOffset,int targetCount,int fromIndex)
=>([CII[CIII)I
attributes:比如Code,就是二進(jìn)制運(yùn)行代碼