Java Class文件

類文件(.class文件擴展名)是包含Java字節碼 ByteCode的文件,可以在Java虛擬機上執行,每個類文件包含了一個類,接口或者模塊(Java 9)的定義

Java程序(.java 文件)可以通過 Java compiler 生成字節碼文件,其他基于JVM的語言也都可以通過自己的編譯器生成字節碼文件,例如Scala,Groovy等

JVM是與平臺無關的,類文件可以在多個平臺上執行,這使得相應的語言也與平臺無關。

Class類文件的結構

類文件由8位字節流組成, 多字節數據使用big-endian的方式存儲
類文件是按照ClassFile結構生成的字節流,字段連續存儲,沒有任何填充或對齊。
Class文件格式采是用類C的結構符號表示的偽結構存儲數據,有兩種數據類型,無符號數(u1,u2,u4,u8)和表(*_info)

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

Class 文件中涉及類/方法等名稱和描述

名稱

Binary Class and Interface Names
全限定名稱,也叫二進制名稱
例如 Thread正常的二進制名稱為 java.lang.Thread ,但是因為一些歷史原因,內部格式下,.被替換成了正斜線/,使用CONSTANT_Utf8_info結構(即Utf8編碼的字符串常量)表示其為java/lang/Thread

Unqualified Names
非限定名稱,即簡單名稱,例如Thread

描述符

描述符是表示字段或方法類型(type)的字符串,使用modified UTF-8(UTF-8縮略編碼)

Field Descriptors
基本數據類型用一個大寫字符表示,int對應 I
對象類型使用一個L加上全限定,末尾加上分號;表示,Object對應Ljava/lang/Object;
數組每個維度使用一個前置[表示,double[][][]對應[[[D

Interpretation of field descriptors

Method Descriptors
由零個或者多個參數描述符,加上一個返回值描述符組成
( {ParameterDescriptor} ) ReturnDescriptor

Object m(int i, double d, Thread t) {...}
對應
(IDLjava/lang/Thread;)Ljava/lang/Object;


magic & version

魔數magic number :識別類文件格式,值為0xCAFEBABE
版本號:M.m(主版本號M,副版本號 m)
major version從45開始的,每個大版本號向上加1
JDk1.1.* 支持45.0 到 45.65535
JDk1.8.* 支持45.0 到 52.65535
JDk1.k.* 支持主版本號45.0 到 44+k.0 (k>=2)

常量池

常量池數目constant_pool_count,數目等于常量表的條目數+1
常量池constant_pool是一張表,結構化的表示各種字符串常量,類和接口名稱,字段名稱等,表索引為1到constant_pool_count - 1

它的用處在于:Java虛擬機指令不依賴于運行時的布局,編譯時沒有鏈接這一步,所以指令引用的是constant_pool表中的符號信息

通用結構

cp_info {
    u1 tag;
    u1 info[];
}

表中的每一項都以一個1byte的標志位開頭,指明該項的常量類型,之后是緊跟相應的內容,每種類型都有自己的結構

Constant pool tags

CONSTANT_Class_info 結構

CONSTANT_Class_info {
      u1 tag;
      u2 name_index;
}

tag :CONSTANT_Class (7)
name_index:是constant_pool中有效的索引,其對應的位置必定是一個CONSTANT_Utf8_info結構,表示類或接口的名稱

CONSTANT_Utf8_info 結構

CONSTANT_Utf8_info {
      u1 tag;
      u2 length;
      u1 bytes[length];
}

tag :CONSTANT_Utf8 (1)
length:長度,限定了最大長度為65535
bytes[]:Modified UTF-8形式的字符串

CONSTANT_Fieldref_info 結構
用于類加載過程中的解析

CONSTANT_Fieldref_info {
      u1 tag;
      u2 class_index;
      u2 name_and_type_index;
}

CONSTANT_Fieldref_info, CONSTANT_Methodref_info, CONSTANT_InterfaceMethodref_info三種常量結構相似, tag作為標識,class_index指向相應的類或接口類型信息的常量,name_and_type_index指向CONSTANT_NameAndType_info結構,表示方法或字段的名稱和描述符

訪問標志 access_flags

類或接口的訪問權限和屬性的標志掩碼

Class access and property modifiers

自身和父類的信息 this_class / super_class

u2類型,指向CONSTANT_Class_info的索引,父類的索引可以為0(java.lang.Object沒有父類),可以獲取對應的類名稱

接口信息 interfaces_count / interfaces[]

描述了該類擴展的接口信息,interfaces[i] 都是constant_pool表中的CONSTANT_Class_info的索引, 0 ≤ i < interfaces_count,接口的順序按照源文件中的實現從左向右排列

字段表

fields_countfields表中field_info結構的數目
field_info結構代表了類或接口中所有的字段(類變量class variables(靜態變量),實例變量instance variables(類實例中包含的變量)),但是不包含他們的父類或者父接口繼承來的字段

field_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}
Field access and property flags

name_index:指向CONSTANT_Utf8_info結構的索引,表示一個有效的非限定名稱
descriptor_index:指向CONSTANT_Utf8_info結構的索引,表示字段的描述符

之后是屬性信息,存儲一些額外的信息,例如對于final static int m = 1,有ConstantValue屬性,包含靜態變量的賦值信息。

方法表

method_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

同字段表類似,訪問標識有部分不同


Method access and property flags

方法中的Java代碼,經過編譯器,編譯成字節碼格式之后,存放在方法的屬性表內的Code屬性內
方法表中可能會有編譯器自己添加的方法,例如<init><clinit>

屬性表

ClassFile, field_info, method_info, and Code_attribute 結構中,都含有屬性
Java 9共有26種預定義的屬性

Predefined class file attributes

每個屬性的名稱用CONSTANT_Utf8_info表示,屬性的結構如下

attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
}

Code屬性

是可變長度的屬性,包含了一個方法的JVM指令和輔助信息
nativeabstract類沒有Code屬性

//Code 屬性的結構
Code_attribute {
    u2 attribute_name_index; //對應一個`CONSTANT_Utf8_info `索引,內容是Code
    u4 attribute_length;
    u2 max_stack; //operand stack 操作數棧的最大深度
    u2 max_locals;//局部變量數組的長度
    u4 code_length; //長度小于65536
    u1 code[code_length];//字節碼指令
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc; //在code數組中的起點和終點[start_pa, end_pc)
        u2 handler_pc; //異常處理對應的字節碼起始位置
        u2 catch_type;// 是常量池中 CONSTANT_Class_info的索引,表示捕獲的異常類型,為0則處理任何異常 
    } exception_table[exception_table_length];//異常表
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

Exception屬性

聲明所有的受查異常(checked exception,不是派生于ErrorRuntimeException的其他所有異常)

Exceptions_attribute {
    u2 attribute_name_index; //索引指向`CONSTANT_Utf8_info `表示"Exceptions"
    u4 attribute_length;
    u2 number_of_exceptions;
    u2 exception_index_table[number_of_exceptions]; //索引指向`CONSTANT_Class_info`,表示受查異常的類型
}

LineNumberTable

出現在Code屬性的attributes表中,顯示code字節碼和相應java源文件的行號
用于調試,以及拋出異常時,顯示出錯的行號

LineNumberTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 line_number_table_length;
    {   u2 start_pc;
        u2 line_number;
    } line_number_table[line_number_table_length];
}

LocalVariableTypeTable

局部變量表,出現在Code屬性的attributes表中,用來在調試過程中描述局部變量的具體類型

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {   u2 start_pc; //對應局部變量的開始位置
        u2 length;//作用域[start_pc, start_pc + length)
        u2 name_index;//名稱
        u2 signature_index;//簽名信息,和描述符類似,保留了泛型類型
        u2 index;//局部變量在當前棧幀局部變量表中的位置索引
    } local_variable_table[local_variable_table_length];
}
函數示例

SourceFile

記錄源碼文件的名稱

Signature

Signature_attribute {
    u2 attribute_name_index; // "Signature"
    u4 attribute_length;  //必定是2
    u2 signature_index; //對應CONSTANT_Utf8_info,表示類,接口,構造器,方法,字段的簽名
}

Java字節碼的方法的特征簽名,包含返回值和受查異常表(詳細信息,參考jvms9 4.7.9.1)
[TypeParameters] ( {JavaTypeSignature} ) Result {ThrowsSignature}

InnerClass

記錄內部類和宿主類之間的關聯

InnerClasses_attribute {
    u2 attribute_name_index; 
    u4 attribute_length;
    u2 number_of_classes;
    {   u2 inner_class_info_index;//內部類或接口信息CONSTANT_Class_info
        u2 outer_class_info_index;//外部類或接口信息CONSTANT_Class_info
        u2 inner_name_index;//內部類的名稱CONSTANT_Class_info,匿名內部類名稱為0
        u2 inner_class_access_flags;
    } classes[number_of_classes];
}
Nested class access and property flags

ConstantValue

靜態變量相關的一個定長屬性

ConstantValue_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 constantvalue_index;
}
常量池中對應字段的類型

javap

反編譯Class文件,沒有選項時輸出包,類里的protected和public字段和方法

用法:javap [options] classfile

  • -verbose 打印細節,可以查看常量表,棧大小,各方法的 locals 及 args 數等
  • -p -private 顯示所有的類和成員
  • -c 輸出類中各方法的 Java 字節碼的指令
  • -s signatures,輸出內部類型簽名

Reference:
Java Language and Virtual Machine Specifications
The Java? Virtual Machine Specification Java SE 9 Edition

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容

  • Java代碼必須要被編譯成class文件后,虛擬機才能夠加載運行,要搞清楚Java的類加載機制,首先必須要理解Cl...
    云飛揚1閱讀 9,537評論 2 61
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 轉自 http://blog.csdn.net/wen7280/article/details/53856790 ...
    云狗狗狗狗狗閱讀 977評論 0 1
  • “《酥油》 是對我們每個人內在力量的最好詮釋。其實夢想、愛與勇氣從來都貯藏在我們的內心,從未遠去。也許只要一...
    流年微涼涼閱讀 533評論 8 5