[一]class 文件淺析 .class文件格式詳解 字段方法屬性常量池字段 class文件屬性表 數據類型 數據結構

前言概述

 本文旨在講解class文件的總體結構信息,閱讀本文後應該能夠完整的瞭解class文件的格式以及各個部分的邏輯組成含義
 
class文件包含了java虛擬機指令集 和  符號表   以及若干其餘輔助信息.
 
class文件是一組以8位字節爲基礎單位的二進制字節流
各個數據項按照順序緊湊的排列在Class文件中,中間沒有任何分隔符號 
class文件採用相似 c結構體的格式存儲數據
數據類型只有兩種
無符號數  和 類c結構體的   表是由無符號數或者其餘的表構成的
 
整個class文件就是一張表
不管無符號數仍是表,當須要描述同一類型但數量不定的多個數據時,常常會使用一個前置的容量計數器用於指示接下來的數據個數,而後是若干個連續的數據項 
 
class文件主要內容爲:  類自己的信息  字段 方法  常量池 以及方法中的Code屬性  再就是一些相關的輔助信息 
類自己的信息類自己有一些必備的描述信息,好比類名 訪問修飾符 繼承關係等
字段用於描述接口或者類中聲明的變量
字段包括類變量以及實例變量,不包括局部變量 他有訪問標誌 名稱 描述符信息
方法用於描述方法表信息  相似字段 也有訪問標誌 名稱 描述符信息
常量池能夠理解爲Class文件的資源倉庫,因此他是與其餘項目關聯最多的數據類型
主要是兩大類:  字面量 以及符號引用 
字面量接近java語言層面的常量概念 好比文本字符串  聲明爲final常量的值
符號引用包括:
類和接口的全限定名
字段的名稱和描述符
方法的名稱和描述符
虛擬機加載class文件的時候動態連接,因此class文件中不會保存方法的最終內存佈局, 還須要轉換
虛擬機運行時從常量池中得到對應的符號引用,而後在建立或者運行時解析翻譯到具體的內存地址中
Code屬性存放的Java方法的內容,位於方法method_info  內
存放的是java方法通過編譯器編譯成的字節碼指令  說白了存放的就是代碼的編譯後形式
 
概述:
class文件做爲JVM的"機器語言" 主要包括兩部分的信息,基礎信息以及附加信息
基礎信息爲源代碼中呈現的信息
類自身信息/字段/方法用於描述源代碼中的類/字段/方法
常量池中保存了資源信息,好比字段的名字 方法的描述符等
方法中的code屬性保存了方法中的代碼的執行邏輯
額外信息爲虛擬機執行過程當中或者字節碼指令執行所須要的信息
爲了保證虛擬機可以正確的加載class文件
另外虛擬機加載類還須要作一些額外的工做好比校驗信息等
字節碼指令的執行可能還須要一些額外的信息
這些額外的信息一般也是保存在常量池中或者以屬性的形式出現
 
因此想要理解class文件的內容,就須要從這兩個方面出發
基礎信息以及額外附加信息
基礎信息是對於源代碼的映射
給出任意一段java代碼,源代碼中到底有哪些信息呢?
好比
類的全限定名  類的屬性信息 訪問權限等
字段的名稱 類型信息 訪問權限等
方法的名稱 方法簽名 返回值類型 訪問權限等
類或者方法或者字段 有沒有註解?
類的父類是什麼?
類繼承了哪些接口? 等等等等
其實換句話說你全部使用依賴的功能,都須要有底層的數據來支撐
 
額外的附加信息主要涉及到字節碼指令以及虛擬機加載相關原理,額外的附加信息是附屬於基本信息的,他們滲透在基本信息裏面
因此下面的說明中,咱們以基礎信息爲綱要,涉及到的附加信息會說明或者從功能上看出來是做爲附加信息
 

class文件的數據格式瞭解

 
class文件包含了虛擬機所須要知道的,關於類或者接口的全部信息
 
結構體
他的基本數據類型爲無符號數,以及表   表  是 數據組織結構相似於C語言中的結構體的的一種形式
爲了更好地理解這種形式的邏輯,不瞭解C語言的,能夠稍微瞭解一點結構體的形式,更有利於理解class文件的數據形式
struct 結構體名
{
    類型名1 成員名1;
    類型名2 成員名2;
                        .....
    類型名n 成員名n;
};
好比
struct student
{
char name[10];
char sex;
int age;
float score;
};
他的每一個元素的數據類型均可以不相同 
並且每一個字段自己也能夠是指向另一個數據項的地址 
也相似與數據庫中的關聯字段ID,這個ID在另外一個表中有表明一整條的記錄
好比學生表有addressId字段,用於關聯地址信息
地址是一條完整的記錄,其中可能包括 國家地區 省市 鄉鎮等等字段值
 

class文件中的數據類型

每個class文件都是由字節流組成
一個字節8位
全部的16位 32位 和 64位數據長度均可以經過構形成2個 4個或者8個字節來表示
多字節的數據將會大端排序(高位字節在地址最低位 )
ps: 所謂大小端
image_5b83663b_d7c
 
 
對於字節的描述,java虛擬機規範中使用u1  u2  u4  u8來分別表示1,2,4和8 個字節的無符號數
 
基本數據類型爲u1,u2,u4,u8  
複雜的數據類型由相似結構體的形式來組織無符號數或者是類結構體的形式  能夠稱之爲 表  也就是說表 裏面能夠有表
好比常量池表中的數據結構爲
cp_info{
u1 tag;
u1 info[ ]
}
因此說
class文件的形式是一張巨大的表,是一個二進制字節流
只有兩種數據表示形式 無符號數   以及   表(結構體 複合的數據結構)
各個數據項嚴格的按照順序存放,之間沒有填充或者對齊,這也是爲什麼編譯後代碼如此緊湊的緣由之一
基本數據類型爲: u1  u2   u4  u8
 
 

class文件的數據組織格式解讀

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文件是一張表
這張表裏面 記錄了class文件自己的相關信息 好比magic 以及版本號
class文件中類索引 this_class  父類索引 super_class 以及接口集合 interfaces 三個數據項肯定了類的繼承關係
 
同時又記錄了字段 方法 以及屬性信息
 
仍是以以前的例子爲例
源代碼
public class HelloWorld {
private int x;
private String y;
public void fun() {
}
public static void main(String[] args) {
System.out.println("hello world");
}
}

 

使用Javap解析後的數據
image_5b83663b_4831
 
 
使用WinHex打開.class 文件 的部分結果
image_5b83663b_1bd2
咱們對照着class文件的結構進行解析
 
注意:
上圖中一列是一個字節 8位 也就是至關於u1   4位表示一個十六進制數
因此一列表示兩個十六進制數
第一項 u4            magic
image_5b83663b_22a4 
複合class文件魔數設置0xCAFEBABE
 

第二項  u2            minor_version
image_5b83663b_2241
第三項  u2            major_version
image_5b83663b_5ba3
因此說 主版本號爲 52(34是十六進制) 次版本號爲0
與javap解析後的數據吻合
image_5b83663b_6982

 
 
第四項 u2            constant_pool_count
image_5b83663b_29c4
十六機制27  十進制39
能夠看到javap解析後的Constant pool:中總共有從#1 到 #38 
常量池計數器constant_pool_count的值等於常量表中的成員數加1
常量池標的索引值只有大於0 且小於constant_pool_count時纔有效
因此此處解析也是對的
 
第五項 cp_info        constant_pool[constant_pool_count-1]
他是常量池
常量池表中的全部項目的格式爲

cp_info{ html

u1 tag; java

u1 info[]; web

}數據庫

此處只是一個格式,表示有一個tag u1  還有不定個數的u1
具體形式由tag的值決定

由於常量池計數爲39
常量池中個數爲[constant_pool_count-1]因此是38
也就是接下來會有38個
{u1 和 多個u1 } 這種形式的數據組合


第一個tag
image_5b83663b_238e
tag = 7 表示 CONSTNT_Class
結構爲

CONSTANT_Class_info{ 編程

u1 tag; bootstrap

u2 name_index; 數組

}數據結構

因此tag 以後,接下來有一個u2 表示name_index
image_5b83663b_5df3
name_index 的值是常量池中的一個索引
他指向的是2號索引
也就是
image_5b83663b_33a

在接下來的一個u1  是下一個常量池數據項的tag
image_5b83663b_7117
tag 爲1 表示CONSTANT_Utf8
他的結構爲

CONSTANT_Utf8_info{ 架構

u1 tag; 併發

u2 length;

u1 bytes[length];

}

因此接下來的兩個爲length
image_5b83663b_65d8
表示長度爲10
在接下來是數組的起始地址,長度爲10
那麼就是10個u1
image_5b83663b_d3b
咱們翻一下ASCII碼錶,對照下十六進制與字符
48        H
65        e
6C        l
6C        l
6F        o
57        W
6F        o
72        r
6C        l
64        d 
也就是HelloWorld  這其實就是咱們的類名
image_5b83663b_40f

 
不在繼續一一比對,你可使用javap 進行查看
這是官方提供的class文件的解析工具
 
總結:
class文件的存儲形式就是一個二進制字節流
使用相似結構體的形式
將源代碼映射的基礎信息以及運行時必要的輔助信息,而這些基礎信息也都已經被分割爲最小的數據單位
進行合理緊湊的組織起來
 
image_5b83663b_1ecf
 
 
 
class文件詳解
 

classFile文件格式

ClassFile {
u4 magic;//惟一做用是肯定這個文件是否爲一個能被虛擬機所接受的class文件。魔數值固定爲0xCAFEBABE,不會改變
u2 minor_version;//惟一做用是肯定這個文件是否爲一個能被虛擬機所接受的class文件。魔數值固定爲0xCAFEBABE,不會改變
u2 major_version;//主版本號
u2 constant_pool_count;//常量池計數  值等於常量池表中的成員個數加1
cp_info constant_pool[constant_pool_count-1];//常量池 1~ constant_pool_count-1 爲索引
u2 access_flags;//訪問標誌以及類型信息
u2 this_class;//當前類索引 指向常量池中一個CONSTANT_Class_info
u2 super_class;//父類索引 0 或者指向常量池中一個CONSTANT_Class_info
u2 interfaces_count;//直接超接口數量
u2 interfaces[interfaces_count];//接口表
u2 fields_count;//字段個數 static類變量或者非sttic的實例變量 不包括繼承的
field_info fields[fields_count];//字段表
u2 methods_count;//方法個數 全部方法 但不包括繼承而來的
method_info methods[methods_count];//方法表
u2 attributes_count;//屬性個數
attribute_info attributes[attributes_count];/屬性表
}

 

從class文件的數據結構上來看,主要有下面幾部分信息內容
class文件自己的信息   magic  minor_version  minor_version
類自己的信息   access_flags   this_class  super_class     interfaces_count    interfaces[interfaces_count]
常量信息   constant_pool_count     constant_pool[constant_pool_count-1]
字段   fields_count     fields[fields_count]
方法   methods_count      methods[methods_count]
屬性   attributes_count     attributes[attributes_count]
 

各類名稱的內部表示形式

 
在進入更加詳細的說明以前,有一部份內容必須提早說一下
那就是一些內部名稱數據的表示形式
就好像編碼同樣,亦或者理解成書寫格式與規範,好比咱們會把姓寫在名的前面
對於class文件中描述的一些信息,咱們有固定的格式的信息描述符號
好比下面會提到的咱們用  D表示是double類型
 
主要涉及兩部份內容  名稱 和描述符

名稱描述

類和接口的二進制名稱
class文件中的類和接口的二進制名稱 是經過全限定名稱來進行表示的
稱之爲二進制名稱
注意,全限定名的分割形式再也不是 英文句號 .  而是  /   好比 java/lang/System
非限定名
方法名 字段名  局部變量名以及形式參數的名都採用非限定名的形式
 

描述符

分爲字段描述符/方法描述符
字段描述符
image_5b83663b_3e48
上面截圖自The Java Virtual Machine Specification, Java SE 8 Edition  
他表示字段描述符使用FieldType來進行表述
FieldType有包括基本類型/對象類型/數組類型
 
形式是
FieldType
 
B byte [基本類型]  有符號的字節數組
C char [基本類型]  基本多語種平面中的Unicode代碼點 UTF-16
D double [基本類型]  雙精度浮點數
F float [基本類型]  單精度浮點數
I int [基本類型]  整型數
J long [基本類型]  長整數
S short [基本類型]  有符號短整數
Z boolean [基本類型]  布爾值true/false
L ClassName; L ClassName; [對象類型]  ClassName類的實例
[ reference [數組類型]  一維數組
好比int 爲I    Object 爲 L java/lang/Object;    double[][][] d 爲 [[[D
 
方法描述符
image_5b83663b_85f
上面截圖自The Java Virtual Machine Specification, Java SE 8 Edition  
 
 
他表示一個方法描述符由一個參數描述符ParameterDescriptor  和一個返回類型描述符ReturnDescriptor組成
參數類型描述符是:   FieldType 類型
返回類型描述符是:   FieldType類型或者Void類型VoidDescriptor
Void類型描述符 使用的是V來進行表示
形式是
( {ParameterDescriptor} ) ReturnDescriptor
注意:    {}  不是一部分,是想表達和數組似的,也多是多個
 
好比
Object m(int i, double d, Thread t) {...}
他的描述符爲:
(IDLjava/lang/Thread;)Ljava/lang/Object;
 
 

class文件詳解之類自己信息

 
類自己的信息   
access_flags   
this_class  super_class     interfaces_count    interfaces[interfaces_count]       
 
名稱
ACC_PUBLIC  0x0001 聲明爲public 包外訪問
ACC_FINAL 0x0010 final 不容許子類
ACC_SUPER 0x0020 調用invokespecial 須要處理父類
ACC_INTERFACE 0x0200 這是一個接口
ACC_ABSTRACT 0x0400 abstract 抽象的不能被實例化
ACC_SYNTHETIC 0x1000 class文件並不是由java源代碼生成
ACC_ANNOTATION 0x2000 註解
ACC_ENUM 0x4000  枚舉        
 
access_flag 字段爲類的訪問權限標誌以及類型值
this_class  super_class   interfaces[interfaces_count]    構成了類的繼承關係 指向的都是常量池中的CONSTANT_Class_info
對於super_class來講,可能爲0 由於Object沒有父類,其餘全部都須要有對應的值存在

class文件詳解之常量池

 
主要分爲兩類  字面量  符號引用
字面量相似java語言層面的含義  文本字符串 聲明爲final 的常量值
符號引用包括:
類和接口的全限定名
字段的名稱和描述符
方法的名稱和描述符
 
常量池包含了class文件結構及其子結構中引用的全部的,字符串常量,類或者接口名,字段名,以及其餘常量 
 
class文件由無符號數和表結構兩種類型組成
關於名稱的書寫規範格式上面已經進行了描述
可是怎麼表述這些名稱的"字符串" 形式呢? 好比className = "Helloworld" 怎麼保存Helloworld?
另一些基本的數據類型的數據在class文件中又將是如何存放呢?好比 int類型的x=5  這個5又怎麼保存?
字符串以及不一樣數值類型也都不就是一個u1 因此也須要組織形式也就是數據結構 也就是表
 

常量池中的表結構的類型能夠分爲三種類型

基本數據類型,好比 int long的描述形式,
雖然class文件是二進制字節流,最小爲u1  可是這些基本數據類型在邏輯意義上來講,纔是最小的描述單位
用於表述, 用於描述各個部分包含的邏輯內容的表     "結構體" 複合形式的數據類型結構 
中間的映射結構表 至關於數據庫中的中間關係表
 
另外全部的常量池中的數據都是cp_info形式,全部的常量池中的數據都徹底遵循這個格式

 

cp_info{
u1 tag;
u1 info[];
}
只不過info[]具體的格式,由tag來進行決定
也就是說不一樣的tag 那一塊區域的大小以及表示的含義天然是不一樣的
其實tag 跟咱們平時寫代碼時候的類型是一個道理  就是接下來這塊區域的內容的類型標記
 
tag值以下:
也就是總共有下面這些類型的常量池信息
CONSTANT_Class 7                        
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18
 

常量池中的基礎數據類型部分

咱們先說下常量池中的封裝好的數據類型部分
字符串常量
CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}
tag是CONSTANT_Utf8 1
字符串採用改進過的UTF-8編碼表示
接下來是編碼後的字符串佔用字節數以及字符串
class文件中的方法字段名稱都是此類型
 
 
int整型 4字節
CONSTANT_Integer_info {
    u1 tag;
    u4 bytes;
}
tag爲CONSTANT_Integer  3
大端排序的int值
 
 
單精度浮點型 float 4字節
CONSTANT_Float_info {
    u1 tag;
    u4 bytes;
}
tag爲CONSTANT_Float  4
大端排序  IEEE754單精度格式   的floa值
 
long與double 是64位 8個字節
分爲4個高字節和4個低字節
 
long 長整型 8字節
CONSTANT_Long_info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}
tag爲CONSTANT_Long 5
大端排序的long值
 
 
雙精度浮點型 double 8字節
CONSTANT_Double_info {
    u1 tag;
    u4 high_bytes;
    u4 low_bytes;
}
 
tag爲CONSTANT_Double 6
大端排序的 double值
 
除了基本數據類型其餘的就是複合數據類型
全部的複合數據類型基本上都會包含其餘的數據結構 
這種包含方式使用的就是索引 #xxx的形式, 指向常量池中的另一項數據
 

常量池中的中間關係映射類型部分


CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
}
tag爲 CONSTANT_NameAndType (12)
NameAndType  就是名稱和類型的意思
對於方法 / 字段    來講,
他們都有變量名稱或者方法名稱
他們也都有變量類型和方法簽名(方法的類型)
NameAndType 是做爲一箇中間表形式的數據結構
字段/方法中都有一個索引指向他,他又指向了實際的名稱和類型
不論是方法名稱仍是字段名稱  不論是方法簽名仍是字段類型都是字符常量的形式
name_index 和 descriptor_index 指向的都是CONSTANT_Utf8_info

常量池中的複合數據類型部分

 
String類型的常量對象
CONSTANT_String_info {
    u1 tag;
    u2 string_index;
}
tag爲CONSTANT_String 8
他表示的是String類型的數據,咱們知道String是常量
字符串常量是用CONSTANT_Utf8_info進行表示的
因此 String_index指向的就是對應的CONSTANT_Utf8_info的"行號"
 
 
方法類型
CONSTANT_MethodType_info {
    u1 tag;
    u2 descriptor_index;
}
CONSTANT_MethodType  16
CONSTANT_NameAndType_info 是一個用於字段或者方法結構中的中間結構,包含了名稱和類型
CONSTANT_MethodType_info  僅僅表示的就是方法簽名
方法簽名對應的是CONSTANT_Utf8_info
因此descriptor_index  指向 方法類型描述符的CONSTANT_Utf8_info
 
類或接口
CONSTANT_Class_info {
    u1 tag;
    u2 name_index;
}
tag 爲CONSTANT_Class 7
名稱天然是字符串常量也就是CONSTANT_Utf8_info
因此 name_index指向常量池中的 CONSTANT_Utf8_info

 
字段
CONSTANT_Fieldref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
CONSTANT_Fieldref  9
class_index 表示當前字段 對應或者說所屬的     類或者接口  類和接口均可能
class_index指向CONSTANT_Class_info
name_and_type_index 表示當前字段的名稱和類型
name_and_type_index指向CONSTANT_NameAndType_info
 
 
方法
CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
CONSTANT_Methodref 10
class_index 表示當前方法 對應或者說所屬的類,必須是類,不能是接口
class_index指向CONSTANT_Class_info
name_and_type_index 表示當前方法的名稱和方法簽名
name_and_type_index指向CONSTANT_NameAndType_info
 
 
接口方法
CONSTANT_InterfaceMethodref_info {
    u1 tag;
    u2 class_index;
    u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref 11
class_index 表示當前方法 對應或者說所屬的接口,必須是接口 不能是類
class_index指向CONSTANT_Class_info
name_and_type_index 表示當前方法的名稱和方法簽名
name_and_type_index指向CONSTANT_NameAndType_info
 
 
方法調用
CONSTANT_MethodHandle_info {
    u1 tag;
    u1 reference_kind;
    u2 reference_index;
}
CONSTANT_MethodHandle  15
方法調用,顧名思義也就是描述 方法的調用
對於一個方法調用來講,方法可能有不一樣的類型,不一樣的類型有不一樣的操做對象
reference_kind 正是描述方法的調用類型
reference_index 描述的是方法的操做目標
reference_kind 的值爲1~9 他的類型決定了方法句柄的類型
句柄類型的值表示方法句柄中字節碼行爲
 
用於表示invokedynamic指令
CONSTANT_InvokeDynamic_info {
    u1 tag;
    u2 bootstrap_method_attr_index;
    u2 name_and_type_index;
}
tag爲CONSTANT_InvokeDynamic   18
CONSTANT_InvokeDynamic_info是爲了字節碼指令 invokedynamic  使用的
invokedynamic是爲了更好的支持動態類型語言,Java7經過JSR292給JVM增長的一條新的字節碼指令
bootstrap_method_attr_index  的值必須是對當前Class文件中引導方法表的bootstrap_methods[]
數組的有效索引
name_and_type_index 指向CONSTANT_NameAndType 表示方法名和方法描述符
 

class文件詳解之字段

字段表field_info 用於描述接口或者類中聲明的變量
包括類變量 以及 實例變量  不包括方法內部聲明的局部變量
 
能夠包括的信息包括
  • 字段的做用域 public private protected
  • 字段類型 類變量仍是實例變量  是否有static修飾
  • 是否爲常量  final
  • 併發可見性 volatile
  • 是否能夠被序列化  transient
  • 字段的數據類型  基本類型 對象 數組  
  • 字段名稱
字段
field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
每一個字段都由field_info結構定義
同一個class文件中不會有兩個字段同時具備相同的字段名和描述符
access_flags 表示字段訪問權限和基本屬性
name_index指向字段的名字 CONSTANT_utf8_info
descriptor_index 指向字段描述符CONSTANT_utf8_info
字段field  包含屬性表,屬性表結構的狀況稍後介紹
 
access_flags字段類型
ACC_PUBLIC 0x0001 字段是否爲public  能夠包外訪問                     
ACC_PRIVATE 0x0002 字段是否爲private 只能本類訪問
ACC_PROTECTED 0x0004 字段是否爲protected 子類能夠訪問
ACC_STATIC 0x0008 字段是否爲static
ACC_FINAL 0x0010 字段是否爲final 
ACC_VOLATILE 0x0040 字段是否爲volatile
ACC_TRANSIENT 0x0080 字段是否爲transient
ACC_SYNTHETIC 0x1000 字段是否由編譯器產生
ACC_ENUM 0x4000 字段是否爲enum
 
如同源代碼中abstract不能和final同時使用,此處的標誌位規則也是如此,有些標誌是互斥的
一個字段最多隻能設置ACC_PUBLIC   ACC_PRIVATE    ACC_PROTECTED 的一種
不能同時設置ACC_FINAL 和 ACC_VOLATILE 
接口中全部字段都具備 ACC_PUBLIC  ACC_STATIC   ACC_FINAL  也能夠設置ACC_SYNTHETIC  其餘的都不行了

class文件詳解之方法

 
方法
method_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
全部方法,包括實例初始化方法以及類或者接口初始化方法
一個class文件中不會有兩個方法具備相同的方法名和描述符
name_index 指向方法名字 CONSTANT_Utf8_info
descriptor_index 表示方法描述符 指向 CONSTANT_Utf8_info
方法也有屬性表
 
access_flag 標誌
基本也同方法的修飾符
ACC_PUBLIC 0x0001 方法是否爲public 包外訪問                 
ACC_PRIVATE 0x0002 方法是否爲private 當前類訪問
ACC_PROTECTED 0x0004 方法是否爲protected 子類訪問
ACC_STATIC 0x0008 方法是否爲static
ACC_FINAL 0x0010 方法是否爲final
ACC_SYNCHRONIZED 0x0020 方法是否爲synchronized
ACC_BRIDGE 0x0040 方法是否爲 編譯器爲了字節碼兼容自動生成的bridge方法
ACC_VARARGS 0x0080 方法是否爲變長參數
ACC_NATIVE 0x0100 方法是否爲native  本地方法
ACC_ABSTRACT 0x0400 方法是否爲abstract 無實現代碼
ACC_STRICT 0x0800 方法是否爲strictfp 使用FP-strict浮點模式
ACC_SYNTHETIC 0x1000 方法是否爲編譯器自動產生而不是由源代碼編譯而來
volatile關鍵字和transient關鍵字不能修飾方法,因此天然也沒有這些個標誌
而synchronized  native  strictfp 和 abstract 關鍵字能夠修飾方法 因此相對於字段中的標誌新增了對應的標誌
 
相似字段,有些方法修飾符標誌也是互斥的
一個方法只能設置ACC_PUBLIC    ACC_PRIVATE   ACC_PROTECTED 中的一種
接口方法能夠設置 除了ACC_PROTECTED  ACC_FINAL ACC_SYNCHRONIZED   ACC_NATIVE   之外的,之外的
版本號小於52 每一個方法必須設置 ACC_PUBLIC  ACC_ABSTRACT
大於等於52 每一個方法必須設置ACC_PUBLIC  或者 ACC_PRIVATE 中的一個
ps: 52 能夠理解爲jdk1.8
若是設置了ACC_ABSTRACT 不能再設置 ACC_FINAL ACC_NATIVE ACC_PRIVATE ACC_STATIC ACC_STRICT  ACC_SYNCHRONIZED
實例初始化方法只能被ACC_PUBLIC ACC_PROTECTED ACC_PRIVATE 其中之一修飾
還能夠設置  ACC_STRICT ACC_VARARGS  ACC_SYNTHETIC  其餘的都不能再設置
類或者接口的初始化方法 由虛擬機自動調用 除了ACC_STRICT之外,其它標誌所有都會被忽略

class文件詳解之屬性

 
經過類 常量池 字段 方法的結構,已經塑造完成了 class文件的基本概念
他們是class文件的基礎骨架
骨架之上還有其餘不少的附屬信息以及好比運行時須要的額外的信息
這些信息大多數不能歸結於一大類,邏輯架構上可能比較散亂,也能夠理解爲雜項信息
這些雜項就都是屬性表的範疇
不過Code屬性比較特殊,他其實也算做是一個骨架部分,或者說一個重要"器官"   他是做爲方法中的代碼編譯後的字節碼形式存在的
只不過由於邏輯上 方法內的代碼字節碼指令顯然是歸屬於某個方法的,因此Code做爲屬性表也能夠理解
 
class文件的ClassFile結構
字段的field_info 結構
方法的method_info結構
另外還有Code屬性
以上四類都包含屬性結構信息
 
全部屬性表的梗概結構爲

attribute_info {

u2 attribute_name_index;

u4 attribute_length;

u1 info[attribute_length];

}

attribute_name_index  表示屬性的名字索引 指向 CONSTANT_Utf8_info
attribute_length就是屬性的長度 
info[attribute_length] 是屬性的具體數據信息
 

全部的屬性按照用途,能夠劃分爲三類

1.對於JVM 正確解讀class文件起關鍵做用的5個屬性
• ConstantValue
• Code
• StackMapTable
• Exceptions
• BootstrapMethods
2.對JavaSE 平臺類庫正確解讀class文件起關鍵做用的12個屬性
• InnerClasses
• EnclosingMethod
• Synthetic
• Signature
• RuntimeVisibleAnnotations
• RuntimeInvisibleAnnotations
• RuntimeVisibleParameterAnnotations
• RuntimeInvisibleParameterAnnotations
• RuntimeVisibleTypeAnnotations
• RuntimeInvisibleTypeAnnotations
• AnnotationDefault
• MethodParameters
對JVM或者JavaSE平臺類庫可以正確解讀class文件
雖然不起關鍵做用,可是卻能夠做爲實用工具來使用的6個屬性
• SourceFile
• SourceDebugExtension
• LineNumberTable
• LocalVariableTable
• LocalVariableTypeTable
• Deprecated
 
咱們已經知道 屬性出現於 classFile  field_info  method_info  code 中

全部屬性按照位置劃分

屬性 位置 備註 首次出現版本號
SourceFile 
ClassFile 表示class文件的源文件名稱
類獨有屬性
45.3
InnerClasses
ClassFile 內部類相關信息
類獨有屬性
45.3
EnclosingMethod
ClassFile class爲局部類或者匿名類才具備
類獨有屬性
49.0
SourceDebugExtension
ClassFile 可選/保存擴展調試信息/最多一個
類獨有屬性
49.0
BootstrapMethods ClassFile
與   invokedynamic指令
常量池中CONSTANT_InvokeDynamic_info
相關
類獨有屬性
51.0
ConstantValue field_info fina修飾的字段的常量值
字段獨有屬性
45.3
Code method_info java程序方法體中的代碼通過javac編譯器處理後
最終變爲字節碼指令存儲在Code屬性內
Code屬性出如今方法表的屬性集合中
抽象類和接口不存在code屬性
包含了方法的java虛擬機指令及相關輔助信息
方法獨有屬性
45.3
Exceptions method_info 方法可能拋出的已檢查異常列表
方法獨有屬性
45.3
RuntimeVisibleParameterAnnotations,
RuntimeInvisibleParameterAnnotations
method_info 形參上的運行時的註解信息類型
分爲可見和不可見兩種類型
方法獨有屬性
49.0
AnnotationDefault method_info method_info表示註解類型中的元素時
記錄這個元素的默認值
方法獨有屬性
49.0
MethodParameters method_info 形參相關信息,好比參數名稱
方法獨有屬性
52.0
Synthetic classFile
field_info
method_info
Synthetic 標誌編譯器生成
類 字段 方法均可能由編譯器生成
因此三種都有此屬性
45.3
Deprecated classFile
field_info
method_info
語義同@Deprecated
顯然能夠標註在類/接口/字段/方法上
因此三種都有此屬性
45.3
Signature
classFile
field_info
method_info
泛型信息
類接口 字段 方法 都有可能有類型參數
因此三種都有此屬性
49.0
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
classFile
field_info
method_info
類 方法 字段上 運行時註解的可見性
分爲可見不可見兩種類型
三種都有此屬性
49.0
LineNumberTable Code 調試用信息
用於調試器肯定源文件中給定行號所表示的內容,對應於虛擬機中code[]數組中的哪一部分
也就是行號與字節碼指令的對應關係
45.3
LocalVariableTable Code 調試用信息
調試器執行方法過程當中能夠用它來肯定某個局部變量的值
45.3
LocalVariableTypeTable Code
調試用信息
調試器執行方法過程當中能夠用它來肯定某個局部變量的值
49.0
StackMapTable Code 虛擬機類型檢查驗證使用信息 50.0
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
classFile
field_info
method_info
類/方法/字段聲明所使用的類型上面的運行時註解可見性
分爲可見/不可見兩種
三種都有此屬性
52.0
 

變換一種組織形式

咱們以位置爲綱 能夠很清晰的看到四個位置處都有那些信息
classFile
SourceFile
InnerClasses
EnclosingMethod
SourceDebugExtension
BootstrapMethods
Synthetic
Deprecated
Signature
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
field_info
ConstantValue
Synthetic
Deprecated
Signature
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
method_info
Code
Exceptions
RuntimeVisibleParameterAnnotations,
RuntimeInvisibleParameterAnnotations
AnnotationDefault
MethodParameters
Synthetic
Deprecated
Signature
RuntimeVisibleAnnotations,
RuntimeInvisibleAnnotations
RuntimeVisibleTypeAnnotations,
RuntimeInvisibleTypeAnnotations
Code
LineNumberTable
LocalVariableTable
LocalVariableTypeTable
StackMapTable

 
屬性表中的attribute_name_index   都是對應的屬性名稱 指向CONSTANT_Utf8_info 好比Code屬性值爲Code   ConstantValue屬性爲ConstantValue
 

ConstantValue 屬性

通知虛擬機爲靜態變量賦值
只有被static關鍵字修飾的變量纔可使用這個屬性  也就是隻有類變量纔可使用
非static類型的變量也就是實例變量的賦值在構造方法中<init>
類變量能夠再<clinit>方法中  也可使用ConstantValue  屬性
目前編譯器的作法是 若是同時使用final和static來修飾,也就是常量了
若是變量的數據類型是基本類型或者java.lang.String的話,就生成ConstantValue
若是沒有final 或者並不是基本類型或者字符串 選擇在<clinit>中
ConstantValue_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 constantvalue_index;
}
 
 

Code屬性

Code屬性是方法體中的代碼通過編譯處理後,最終的字節碼指令
既然是方法體的內容,若是沒有方法體天然沒有code屬性 好比 接口或者抽象類中就不存在Code屬性  native也不存在
 
Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}
 
attribute_name_index 指向CONSTANT_Utf8_info 常量值 固定爲"Code" 表示屬性的名稱
attribute_length  屬性值長度   屬性表前面6個字節 u2 + u4    再加上attribute_length  就是整個表的長度了
max_stack 操做數棧的最大深度 方法執行任意時刻不會超過這個值,根據值來分配棧幀  
ps:
虛擬機棧是線程私有的,每建立一個線程,虛擬機就會爲這個線程建立一個虛擬機棧
虛擬機棧表示Java方法執行的內存模型,每調用一個方法就會爲每一個方法生成一個棧幀(Stack Frame),用來存儲局部變量表、操做數棧、動態連接、方法出口等信息。
每一個方法被調用和完成的過程,都對應一個棧幀從虛擬機棧上入棧和出棧的過程。
虛擬機棧的生命週期和線程是相同的
max_locals 局部變量表所須要的空間單位個數,能夠理解爲座位 這個位置叫作 Slot  能夠查看javap後的信息
long  double佔用兩個單位  其餘類型一個單位
並非有多少局部變量就是求和計算,由於變量有做用域的生命週期,因此空間能夠複用
編譯器會自動分配 ,而且計算出來這個值, 能夠理解爲 任意時刻最大的所須要空間個數
code_lengthcode 纔是真正的存儲字節碼的,雖然咱們說code屬性就是存儲編譯後的字節碼
code_length指明瞭字節碼指令的長度 字節碼指令爲u1  
讀取一個指令後虛擬機就能夠知道這個字節碼的含義以及這條指令後面是否還有參數
以及參數如何理解
exception_table  異常表表示的是可能出現的代碼執行路徑
表示若是字節碼start_pc行 到 end_pc行,包含頭不包含爲 也就是不包含end_pc 
出現了類型爲catch_type 或者他的子類的異常 catch_type 指向一個CONSTANT_Class_info
轉到handler_pc中處理
        u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
image_5b83663b_986
image_5b83663b_1cff
上面的代碼除了正常執行之外
若是try出現Exception或者子類的異常 轉到catch
若是出現不屬於Exception或者子類的異常 轉到finally
若是catch中出現任何異常,轉到finally
 

StackMapTable屬性

用於虛擬機類型檢查的驗證階段
是爲了一種新的類型檢查驗證器而設置的,新的驗證器在編譯階段將一系列的驗證類型直接記錄在class文件中,
經過檢查這些驗證類型代替了類型推導過程
 
Code屬性表裏最多能夠包含一個StackMapTable
StackMapTable包含0個或者多個棧幀映射
用於表示  執行到該字節碼時局部變量表和操做數棧的驗證類型
類型檢查驗證器會經過檢查目標方法的局部變量和操做數棧所須要的類型來肯定一段字節碼指令是否符合邏輯約束
 
版本號大於等於50的class文件中若是方法的code屬性中沒有附帶StackMapTable屬性,意味着他有一個  隱式的棧幀映射屬性
隱式的棧映射屬性的做用等同於number_of_entries 值爲0的StackMapTable
StackMapTable_attribute {
    u2              attribute_name_index;
    u4              attribute_length;
    u2              number_of_entries;
    stack_map_frame entries[number_of_entries];
}
number_of_entries給出來的是stack_map_frame的個數
union stack_map_frame {
    same_frame;
    same_locals_1_stack_item_frame;
    same_locals_1_stack_item_frame_extended;
    chop_frame;
    same_frame_extended;
    append_frame;
    full_frame;
}
 
 

Exceptions屬性


不是Code中的exception_table   注意區分
列舉出方法中可能拋出的已檢查的異常
也就是方法聲明throws後面的內容
Exceptions_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_exceptions;
    u2 exception_index_table[number_of_exceptions];
}
attribute_name_index 指向名字
attribute_length表示長度
number_of_exceptions  表示個數
exception_index_table 指向常量池中的CONSTANT_Class_info 表示異常類型
 

BootstrapMethods 屬性

保存invokedynamic 指令引用的引導方法限定符
若是某個classFile文件中常量池中至少有一個CONSTANT_InvokeDynamic_info
那麼就必須包含且只能包含一個BootstrapMethods
與invokedynamic指令和java.lang.invoke包關係密切
BootstrapMethods_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 num_bootstrap_methods;
    {  u2 bootstrap_method_ref;
        u2 num_bootstrap_arguments;
        u2 bootstrap_arguments[num_bootstrap_arguments];
    } bootstrap_methods[num_bootstrap_methods];
}
 

InnerClasses  屬性

記錄內部類與宿主類之間的關聯
若是一個類內部定義了內部類,編譯器就會爲以及他所包含的內部類生成InnerClasses屬性
InnerClasses_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 number_of_classes;
    {   u2 inner_class_info_index;
        u2 outer_class_info_index;
        u2 inner_name_index;
        u2 inner_class_access_flags;
    } classes[number_of_classes];
}
 
inner_class_info_index   outer_class_info_index  都是指向常量池中CONSTANT_Utf8_info
分別表明內部類和宿主類的內部引用
inner_name_index指向常量池中CONSTANT_Utf8_info 表示內部類的名稱  匿名內部類 爲0
inner_class_access_flags   內部類的訪問標誌
ACC_PUBLIC 0x0001 內部類是否爲public
ACC_PRIVATE 0x0002 內部類是否爲private
ACC_PROTECTED 0x0004  內部類是否爲protected
ACC_STATIC 0x0008 內部類是否爲static
ACC_FINAL 0x0010 內部類是否爲final
ACC_INTERFACE 0x0200 內部類是否爲interface
ACC_ABSTRACT 0x0400 內部類是否爲abstract
ACC_SYNTHETIC 0x1000 內部類是否爲編譯器自動生成
ACC_ANNOTATION 0x2000 內部類是否爲註解
ACC_ENUM 0x4000 內部類是否爲枚舉
 

Synthetic  屬性

標誌是否有編譯器自動生成   沒有具體的值  只有存在和不存在的說法
Synthetic_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
}
attribute_name_index  指向CONSTANT_Utf8_info  表示 synthetic
attribute_length  固定爲0  也就是麼有值
 

Signature 屬性

可選的屬性   1.5以後 任何    類 接口 初始化方法 或者成員   的泛型簽名若是包含了類型變量 或者   參數化類型
那麼signature 屬性記錄泛型簽名信息
之因此須要是由於泛型擦除機制
反射機制獲取泛型類型 依賴數據就是這個屬性
Signature_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 signature_index;
}
 
 

EnclosingMethod 屬性

位於classFile結果的屬性 當且僅當class爲局部類和匿名內部類時 才具備這個屬性
class_index  表示包含當前類的最內層類
method_index表示當前類是否在某個方法或者構造器中,若是不是 值爲0
EnclosingMethod_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 class_index;
    u2 method_index;
}
 
 

RuntimeVisibleAnnotations 屬性 RuntimeInvisibleAnnotations 屬性

添加在類聲明 字段聲明  方法聲明上面的註解  在運行時的可見狀況
Visible 可見  Invisible不可見
 
ClassFile  field_info method_info中最多隻能有一個RuntimeVisibleAnnotations   或者  RuntimeInvisibleAnnotations
RuntimeVisibleAnnotations   和  RuntimeInvisibleAnnotations  基本一致,  可是 RuntimeInvisibleAnnotations 標誌的不能被反射API訪問
除非虛擬機經過與實現相關的特殊方式保留這些註解,不然,虛擬機將忽略Invisible的註解
num_annotations表示註解的數量
annotations  每一個元素都表示一個註解
 
RuntimeVisibleAnnotations_attribute {
    u2         attribute_name_index;
    u4         attribute_length;
    u2         num_annotations;
    annotation annotations[num_annotations];
}
 
RuntimeInvisibleAnnotations_attribute {
    u2         attribute_name_index;
    u4         attribute_length;
    u2         num_annotations;
    annotation annotations[num_annotations];
}
 
annotation {
    u2 type_index;
    u2 num_element_value_pairs;
    {  u2            element_name_index;
       element_value value;
    } element_value_pairs[num_element_value_pairs];
}
 
type_index 用來表示一個字段描述符,字段描述符表示一個註解類型
和當前annotation 結構所表示的註解一致
num_element_value_pairs  表示註解中的鍵值對 (註解中的參數都是鍵值對)  的個數
element_value_pairs  表明真正的鍵值對
它包括
element_name_index表示鍵    
element_value   表示值
 
element_value {
    u1 tag;
    union {
        u2 const_value_index;
        {   u2 type_name_index;
            u2 const_name_index;
        } enum_const_value;
        u2 class_info_index;
        annotation annotation_value;
        {   u2            num_values;
            element_value values[num_values];
        } array_value;
    } value;
}
 
element_value 表示一個聯合體
tag 使用u1 來表示鍵值對中的值是什麼類型
也就是決定了鍵值對中  值的格式與value 中的哪一項相符合
聯合體總共有五種
const_value_index
enum_const_value
class_info_index 
annotation_value
array_value
 
tag  值表示的類型
B byte const_value_index CONSTANT_Integer
C char const_value_index CONSTANT_Integer
D double const_value_index CONSTANT_Double
F float const_value_index CONSTANT_Float
I int const_value_index CONSTANT_Integer
J long const_value_index CONSTANT_Long
S short const_value_index CONSTANT_Integer
Z boolean const_value_index CONSTANT_Integer
s String const_value_index CONSTANT_Utf8
e Enum類型 enum_const_value 不適用
c Class class_info_index 不適用
@ Annotation類型 annotation_value 不適用
[ Array 類型 array_value 不適用
 
 
 
const_value_index   表示原始類型的常量值 或者String類型的字面量
enum_const_value  表示一個枚舉常量
    type_name_index  指向CONSTANT_Utf8_info 枚舉常量類型的二進制名稱的內部形式
    const_name_index 指向CONSTANT_Utf8_info 枚舉常量的簡單名稱
class_info_index  表示類字面量  CONSTANT_Utf8_info   用於表示返回描述符  返回描述符給出了與該element_value結構所表示的類字面量相對應的類型
若是類字面量是C. class,且C是類、接口或數組類型的名字,那麼對應的類型就是C。常量池中的返回描述符會是ObjectType  或者ArrayType
若是類字面量是p. class,且p是原始類型的名稱,那麼對應的類型就是p    常量池中的返回描述符會是一個BaseType
若是類字面量是void. class,那麼對應的類型就是void。常量池中的返回描述符會是V.
好比Object.class 對應於類型Object 因此常量池中就是Ljava/lang/Object;  而 int.class對應於類型int 常量池中就是I(大寫的i )
annotation_value    表示鍵值對中裏面的值自己又是一個註解
array_value    表示鍵值對的  值   是一個數組
    num_values  給出了當前element_value結構所表示的數組的成員數量
    values   每一個成員對應了當前element_value 結構所表示的數組中的一個元素

RuntimeVisibleTypeAnnotations   屬性    RuntimeInvisibleTypeAnnotations   屬性

classFile field_info  method_info  或者code屬性中都有
好比對於某個類聲明implements後面的類型所加的註解 記錄在classFile結構體的這個屬性裏
好比某個字段聲明中的類型 所加的所有註解記錄在字段的對應屬性裏
 
記錄了標註在對應類聲明  字段聲明 或者方法聲明所使用的類型上面的註解     在運行時的可見狀況
分爲可見和不可見兩種
也記錄了標註在對應方法體重某個表達式所使用的類型上面的運行時可見註解
此外還記錄了標註在泛型類  接口 方法 以及構造器的類型參數聲明上面的註解
Java虛擬機必須使這些註解可供取用
最多隻能有一個
num_annotations  表示註解個數
annotations  表示每個註解 類型爲type_annotation
RuntimeVisibleTypeAnnotations_attribute {
    u2              attribute_name_index;
    u4              attribute_length;
    u2              num_annotations;
    type_annotation annotations[num_annotations];
}
 
RuntimeInvisibleTypeAnnotations_attribute {
    u2              attribute_name_index;
    u4              attribute_length;
    u2              num_annotations;
    type_annotation annotations[num_annotations];
}
 
type_annotation {
    u1 target_type;
    union {
        type_parameter_target;
        supertype_target;
        type_parameter_bound_target;
        empty_target;
        method_formal_parameter_target;
        throws_target;
        localvar_target;
        catch_target;
        offset_target;
        type_argument_target;
    } target_info;
    type_path target_path;
    u2        type_index;
    u2        num_element_value_pairs;
    {   u2            element_name_index;
        element_value value;
    } element_value_pairs[num_element_value_pairs];
}
前三項 target_type target_info 以及 target_path  指出了帶註解的類型所在的精確位置  target表示那個類型
後面type_index   num_element_value_pairs       element_value_pairs指出了註解自己的類型以及鍵值對
 

RuntimeVisibleParameterAnnotations    屬性   RuntimeInvisibleParameterAnnotations   屬性

保存標註在對應方法的形式參數聲明上面的註解的運行時可見狀態
分爲可見和不可見兩種
num_parameters  形參個數
parameter_annotations 每一個元素表示一個形式參數的運行時註解  第 n項,表示方法描述符中的第  n  個形式參數
RuntimeVisibleParameterAnnotations_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 num_parameters;
    {   u2         num_annotations;
        annotation annotations[num_annotations];
    } parameter_annotations[num_parameters];
}
 
RuntimeInvisibleParameterAnnotations_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 num_parameters;
    {   u2         num_annotations;
        annotation annotations[num_annotations];
    } parameter_annotations[num_parameters];
}
 

AnnotationDefault   屬性

若是一個method_info 是用來表述註解類型中的元素的
該結構體的屬性表中最多隻能有一個AnnotationDefault
AnnotationDefault屬性記錄了由method_info 結構所表示的那個元素的默認值
default_value 表示由AnnotationDefault屬性外圍的method_info結構所描述的那個註解類型元素的默認值
說白了這個結構有用的纔是default_value
AnnotationDefault_attribute {
    u2            attribute_name_index;
    u4            attribute_length;
    element_value default_value;
}
 
 

MethodParameters    屬性

形參相關的一些信息 好比參數名稱
parameters_count  表示本屬性外圍method_info 結構裏面的descriptor_index所引用的那個方法描述符中,有多少個參數描述符
parameters  表示實際的參數

name_index 要麼是0要麼指向CONSTANT_Utf8_info 表示一個有效的非限定名 用來指代某個形式參數
access_flags ACC_FINAL 0x0010 形參爲final
                      ACC_SYNTHETIC 0x1000 形參沒有顯式或者隱式的在源代碼中聲明,由編譯器生成
                      ACC_MANDATED 0x8000 形參是隱式聲明,也就是編程語言規範對全部的編譯器的要求必須生成

MethodParameters_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 parameters_count;
    {  u2 name_index;
        u2 access_flags;
    } parameters[parameters_count];
}
 

 

sourceFile  屬性

class文件的源文件名,屬性是可選的能夠關閉
可是一旦關閉,當拋出異常時 不會顯示出錯代碼所歸屬的文件名稱
SourceFile_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 sourcefile_index;
}
 
sourcefile_index 指向的是常量池中的CONSTANT_Utf8_info 表示源文件的文件名

SourceDebugExtension   屬性

一個classFile只能包含一個屬性
debug_extension  用於保存擴展調試信息  擴展調試信息對於java虛擬機來講沒有實際的語義 
擴展信息使用改進版的UTF8 編碼的字符串  也能夠說這個就算是另外一種格式的用於表示字符串的結構 
不過他比String類的實例所能表示的字符串更長
SourceDebugExtension_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 debug_extension[attribute_length];
}

LineNumberTable   屬性

Code屬性的屬性表中
源文件中給定的行號表示的內容對應字節碼指令的行號(偏移量)之間的關係
並非運行時必須信息,可是會默認生成到Class文件中
能夠經過參數設置不生成,可是程序運行產生的最主要影響就是當拋出異常時,堆棧中不會顯示出錯的行號
調試時也沒法設置斷點
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];
}
 

LocalVariableTable   屬性

用於描述棧幀中的局部變量表中的變量與java源代碼中定義的變量之間的關係
也能夠不生成,可是可能會致使別人引用方法時,參數名稱丟失
LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {  u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}

LocalVariableTypeTable  屬性

與LocalVariableTable相似,就是descriptor_index  被替換爲了signature_index
主要針對泛型場景
非泛型簽名與描述符基本一致,引入泛型後實際的泛型信息會被擦除 描述符就不足夠準確了
LocalVariableTypeTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_type_table_length;
    {  u2 start_pc;
        u2 length;
        u2 name_index;
        u2 signature_index;
        u2 index;
    } local_variable_type_table[local_variable_type_table_length];
}
 

Deprecated 屬性

語義同語法中的@Deprecated  形式相似Synthetic   標誌屬性  有和沒有的區別
attribute_length 固定爲0
Deprecated_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
}
 

 
class文件的最詳細的介紹
天然是官方文檔
https://docs.oracle.com/javase/specs/index.html
包含多個版本的JDK  
以及兩種格式
image_5b83663c_263e
 
 
另外也有中文版
image_5b83663c_2eff
相關文章
相關標籤/搜索