3 - 類文件結(jié)構(gòu)

  1. 概述
  2. Class文件結(jié)構(gòu)總結(jié)

1.概述

在 Java 中,JVM 可以理解的代碼就叫做字節(jié)碼(即擴(kuò)展名為 .class 的文件),它不面向任何特定的處理器,只面向虛擬機(jī)。Java 語言通過字節(jié)碼的方式,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,同時(shí)又保留了解釋型語言可移植的特點(diǎn)。所以 Java 程序運(yùn)行時(shí)比較高效,而且,由于字節(jié)碼并不針對(duì)一種特定的機(jī)器,因此,Java 程序無須重新編譯便可在多種不同操作系統(tǒng)的計(jì)算機(jī)上運(yùn)行。

.class文件是不同的語言在 Java 虛擬機(jī)之間的重要橋梁,同時(shí)也是支持 Java 跨平臺(tái)很重要的一個(gè)原因。

class文件

2. Class文件結(jié)構(gòu)總結(jié)

根據(jù) Java 虛擬機(jī)規(guī)范,類文件由單個(gè) ClassFile結(jié)構(gòu)組成:
單個(gè)ClassFile的結(jié)構(gòu)為:

ClassFile {
    u4             magic; //Class 文件的標(biāo)志
    u2             minor_version;//Class 的小版本號(hào)
    u2             major_version;//Class 的大版本號(hào)
    u2             constant_pool_count;//常量池的數(shù)量
    cp_info        constant_pool[constant_pool_count-1];//常量池
    u2             access_flags;//Class 的訪問標(biāo)記
    u2             this_class;//當(dāng)前類
    u2             super_class;//父類
    u2             interfaces_count;//接口
    u2             interfaces[interfaces_count];//一個(gè)類可以實(shí)現(xiàn)多個(gè)接口
    u2             fields_count;//Class 文件的字段屬性
    field_info     fields[fields_count];//一個(gè)類會(huì)可以有個(gè)字段
    u2             methods_count;//Class 文件的方法數(shù)量
    method_info    methods[methods_count];//一個(gè)類可以有個(gè)多個(gè)方法
    u2             attributes_count;//此類的屬性表中的屬性數(shù)
    attribute_info attributes[attributes_count];//屬性表集合
}

Class文件字節(jié)碼結(jié)構(gòu)示意圖

Class文件字節(jié)碼結(jié)構(gòu)組織示意圖

2.1 magic number

u4             magic; //Class 文件的標(biāo)志

每個(gè) Class 文件的頭四個(gè)字節(jié)稱為魔數(shù)(Magic Number),它的唯一作用是確定這個(gè)文件是否為一個(gè)能被虛擬機(jī)接收的 Class 文件。

2.2 Class文件版本

u2             minor_version;//Class 的小版本號(hào)
u2             major_version;//Class 的大版本號(hào)

緊接著魔數(shù)的四個(gè)字節(jié)存儲(chǔ)的是 Class 文件的版本號(hào):第五和第六是次版本號(hào),第七和第八是主版本號(hào)。

高版本的 Java 虛擬機(jī)可以執(zhí)行低版本編譯器生成的 Class 文件,但是低版本的 Java 虛擬機(jī)不能執(zhí)行高版本編譯器生成的 Class 文件。所以,我們?cè)趯?shí)際開發(fā)的時(shí)候要確保開發(fā)的的 JDK 版本和生產(chǎn)環(huán)境的 JDK 版本保持一致。

2.3 常量池

u2             constant_pool_count;//常量池的數(shù)量
cp_info        constant_pool[constant_pool_count-1];//常量池

緊接著主次版本號(hào)之后的是常量池,常量池的數(shù)量是 constant_pool_count-1(常量池計(jì)數(shù)器是從1開始計(jì)數(shù)的,將第0項(xiàng)常量空出來是有特殊考慮的,索引值為0代表“不引用任何一個(gè)常量池項(xiàng)”)。

常量池主要存放兩大常量:

  1. 字面量(字面量比較接近于 Java 語言層面的的常量概念)
  • 文本字符串
  • 聲明為 final 的常量值
  1. 符號(hào)引用(編譯方面的概念)
  • 類和接口的全限定名
  • 字段的名稱和描述符
  • 方法的名稱和描述符

常量池中每一項(xiàng)常量都是一個(gè)表,這14種表有一個(gè)共同的特點(diǎn):開始的第一位是一個(gè) u1 類型的標(biāo)志位 -tag 來標(biāo)識(shí)常量的類型,代表當(dāng)前這個(gè)常量屬于哪種常量類型.

常量池中常量的類型

2.4 訪問標(biāo)志

在常量池結(jié)束之后,緊接著的兩個(gè)字節(jié)代表訪問標(biāo)志,這個(gè)標(biāo)志用于識(shí)別一些類或者接口層次的訪問信息。例如:

  • 這個(gè)Class是類還是接口
  • 是否為 public 或者 abstract 類型
  • 是類的話是否聲明為 final
  • ......
類訪問和屬性修飾符

2.5 當(dāng)前類索引,父類索引與接口索引集合

u2             this_class;//當(dāng)前類
u2             super_class;//父類
u2             interfaces_count;//接口
u2             interfaces[interfaces_count];//一個(gè)類可以實(shí)現(xiàn)多個(gè)接口

類索引用于確定這個(gè)類的全限定名,父類索引用于確定這個(gè)類的父類的全限定名,由于 Java 語言的單繼承,所以父類索引只有一個(gè),除了 java.lang.Object 之外,所有的 java 類都有父類,因此除了 java.lang.Object 外,所有 Java 類的父類索引都不為 0。

接口索引集合用來描述這個(gè)類實(shí)現(xiàn)了那些接口,這些被實(shí)現(xiàn)的接口將按implents(如果這個(gè)類本身是接口的話則是extends) 后的接口順序從左到右排列在接口索引集合中.

2.6 字段表集合

u2             fields_count;//Class 文件的字段的個(gè)數(shù)
field_info     fields[fields_count];//一個(gè)類會(huì)可以有多個(gè)字段

字段表(field info)用于描述接口或類中聲明的變量。字段包括類級(jí)變量以及實(shí)例變量,但不包括在方法內(nèi)部聲明的局部變量。

field info(字段表) 的結(jié)構(gòu):

字段表結(jié)構(gòu)
  • access_flags: 字段的作用域(public ,private,protected修飾符),是實(shí)例變量還是類變量(static修飾符),可否被序列化(transient 修飾符),可變性(final),可見性(volatile 修飾符,是否強(qiáng)制從主內(nèi)存讀寫)。
  • name_index: 對(duì)常量池的引用,表示的字段的名稱;
  • descriptor_index: 對(duì)常量池的引用,表示字段和方法的描述符;
  • attributes_count: 一個(gè)字段還會(huì)擁有一些額外的屬性,attributes_count 存放屬性的個(gè)數(shù);
  • attributes[attributes_count]: 存放具體屬性具體內(nèi)容。

上述這些信息中,各個(gè)修飾符都是布爾值,要么有某個(gè)修飾符,要么沒有,很適合使用標(biāo)志位來表示。而字段叫什么名字、字段被定義為什么數(shù)據(jù)類型這些都是無法固定的,只能引用常量池中常量來描述。

字段的access_flags的取值

2.7 方法表集合

u2             methods_count;//Class 文件的方法的數(shù)量
method_info    methods[methods_count];//一個(gè)類可以有個(gè)多個(gè)方法

methods_count 表示方法的數(shù)量,而 method_info 表示的方法表。

Class 文件存儲(chǔ)格式中對(duì)方法的描述與對(duì)字段的描述幾乎采用了完全一致的方式。方法表的結(jié)構(gòu)如同字段表一樣,依次包括了訪問標(biāo)志、名稱索引、描述符索引、屬性表集合幾項(xiàng)。

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

2.8 屬性表集合

u2             attributes_count;//此類的屬性表中的屬性數(shù)
attribute_info attributes[attributes_count];//屬性表集合

在 Class 文件,字段表,方法表中都可以攜帶自己的屬性表集合,以用于描述某些場(chǎng)景專有的信息。與 Class 文件中其它的數(shù)據(jù)項(xiàng)目要求的順序、長(zhǎng)度和內(nèi)容不同,屬性表集合的限制稍微寬松一些,不再要求各個(gè)屬性表具有嚴(yán)格的順序,并且只要不與已有的屬性名重復(fù),任何人實(shí)現(xiàn)的編譯器都可以向?qū)傩员碇袑?入自己定義的屬性信息,Java 虛擬機(jī)運(yùn)行時(shí)會(huì)忽略掉它不認(rèn)識(shí)的屬性。

Reference: https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/jvm/%E7%B1%BB%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84.md

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容