暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

《深入理解Java虚拟机》笔记(1)-Class文件

没意思先生 2020-03-01
135
Class类文件是一组以8个字节为基础单位的的二进制流.文件格式采用一种类C语言结构体的为结构存储数据,结构内只有两种数据类型:
  1. 无符号数:用来描述数字,索引引用,数量值和按UTF-8编码构成的字符串值;
  2. 表:由多个无符号数或者其他表作为数据项构成的复合数据类型,表名基本以_info结尾
Class文件的构成:

1)  魔数(0xCAFEBABE)4个字节;

次版本号(第5,6个字节),主版本号(第7,8个字节)


JDK版本号Class版本号16进制
1.145.0
00 00 00 2D
1.2
46.0
00 00 00 2E
1.3
47.0
00 00 00 2F
1.4
48.0
00 00 00 30
1.5
49.0
00 00 00 31
1.6
50.0
00 00 00 32
1.751.0
00 00 00 33
1.8
52.0
00 00 00 34

2)  常量池(入口u2数据类型表示常量池的容量计数,唯独此容量计数从1开始,0表示不引用任何一个常量池项目).常量池主要存放两大类常量:

    1) 字面量:如文本字符串和被声明为final的常量

    2) 符号引用:如被模块导出或者开放的包;类和接口的全限定名;字段名称和描述符;方法名            称和描述符;方法句柄和方法类型;动态调用点和动态常量;

常量表的项目类型

类型
标志
描述
CONSTANT_Utf8_info
1
UTF-8编码的字符串
CONSTANT_Integer_info
3整型字面量
CONSTANT_Float_info
4
浮点型字面量
CONSTANT_Long_info
5
长整型字面量
CONSTANT_Double_info
6
双精度浮点型字面量
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_MethodHandle_info
15表示方法句柄
CONSTANT_MethodType_info
16表示方法类型
CONSTANT_Dynamic_info
17表示一个动态计算常量
CONSTANT_InvokeDynamic_info
18表示一个动态方法调用点
CONSTANT_Module_info
19表示一个模块
CONSTANT_Package_info
20表示一个模块开放或者导出的包

常量池中常量项的结构总表

常量
项目
类型
描述
CONSTANT_Utf8_info
tag
1bit值为1
length
2bit
UTF-8编码的字符串占用的字符数
bytes
1bit
长度为length的UTF-8编码的字符串
CONSTANT_Integer_info
tag
1bit值为3
bytes
4bit
按照高位在前存储的int值
CONSTANT_Float_info
tag
1bit值为4
bytes
4bit
按照高位在前存储的float值
CONSTANT_Long_info
tag
1bit值为5
bytes
8bit
按照高位在前存储的long值
CONSTANT_Double_info
tag
1bit值为6
bytes
8bit
按照高位在前存储的double值
CONSTANT_Class_info
tag
1bit值为7
index
2bit
指向全限定名常量项的索引
CONSTANT_String_info
tag
1bit值为8
index
2bit
指向字符串字面量的索引
CONSTANT_Fieldref_info
tag
1bit值为9
index2bit
指向声明字段的类或者接口描述符CONSTANT_Class_info的索引项
index
2bit指向字段描述符CONSTANT_NameAndType的索引项
CONSTANT_Methodref_info
tag
1bit
值为10
index
2bit指向声明方法的类描述符CONSTANT_Class_info的索引项
index
2bit指向名称及类型描述符CONSTANT_NameAndType的索引项
CONSTANT_InterfaceMethodref_info
tag
1bit值为11
index
2bit指向声明方法的接口描述符CONSTANT_Class_info的索引项
index
2bit指向名称及类型描述符CONSTANT_NameAndType的索引项
CONSTANT_NameAndType_info
tag
1bit值为12
index
2bit指向该字段或者方法名称常量项的索引
index
2bit指向该字段或者方法描述符常量项的索引
CONSTANT_MethodHandle_info
tag
1bit值为15
reference_kind
1bit值为1-9之间.它决定方法句柄的类型方法句柄类型的值,表示方法句柄的字节码行为
reference_kind
2bit值必须是对常量池的有效索引
CONSTANT_MethodType_info
tag
1bit
值为16
descriptor_index
2bit值必须是对常量池的有效索引,该项必须是CONSTANT_Utf8_info结构,表示方法的描述符
CONSTANT_Dynamic_info
tag
1bit
值为16
bootstrap_method_attr_index
2bit
值必须是对class文件引导方法表的bootstrap_method[]数组的有效索引
name_and_type_index
2bit
值必须是对常量池的有效索引,该项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符
CONSTANT_InvokeDynamic_info
tag
1bit值为18
bootstrap_method_attr_index2bit
值必须是对class文件引导方法表的bootstrap_method[]数组的有效索引
name_and_type_index
2bit值必须是对常量池的有效索引,该项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符
CONSTANT_Module_info
tag
1bit
值为19
name_index
2bit
值必须是对常量池的有效索引,该项必须是CONSTANT_Utf8_info结构,表示模块名称
CONSTANT_Package_info
tag
1bit
值为20
name_index
2bit
值必须是对常量池的有效索引,该项必须是CONSTANT_Utf8_info结构,表示包名称

3) 访问标志(2字节):标识一些类或者接口层次的访问信息

标志名称
标志值
含义
ACC_PUBLIC
0x0001
是否为public类型
ACC_FINAL0x0010是否声明为final,只有类能设置
ACC_SUPER0x0020是否允许使用invokespecial字节码指令的新语义,JDK1.0.2后皆为true
ACC_INTERFACE0x0200标识这是一个接口
ACC_ABSTRACE0x0400是否为abstract类型,接口或抽象类为true,其他为false
ACC_SYNTHETIC0x1000标识这个类并非由用户代码产生
ACC_ANNOTATION0x2000标识这是一个注解
ACC_ENUM0x4000标识这是一个枚举
ACC_MODULE0x8000标识这是一个模块

4) 类索引、父类索引与接口索引集合(入口u2数据类型表示集合的容量计数):类索引用于确认这个类的全限定名;父类索引用于确认类的父类的全限定名(除了Object类,其他类的索引都不为0);接口索引集合按implements关键字或extends关键字后的接口顺序从左到右排列在集合里.

5) 字段表集合(入口u2数据类型表示集合的容量计数):用于描述接口或者类中声明的变量.

    字段表结构:

类型
名称
数量
2bit
access_flags
1
2bit
name_index
1
2bit
descriptor_index1
2bit
attributes_count
1
attribute_info
attributes
attributes_count

   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_ENUM0x4000
字段是否enum

描述符是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值.常见描述符标志字符含义:


标识字符
含义
B
基本类型byte
C
基本类型char
D
基本类型double
F
基本类型float
I
基本类型int
J基本类型long
S
基本类型short
Z
基本类型boolean
V
特殊类型void
L
对象类型

对于数组类型,每个维度使用一个前置的" [ "字符描述;用描述符描述方法时,按照先参数列表、后返回值的顺序描述,参数列表按参数的顺序放在小括号()内.

6) 方法表集合:

    方法表结构:

类型
名称
数量
2bit
access_flags
1
2bit
name_index
1
2bitdescriptor_index1
2bitattributes_count1
attribute_info
attributes
attributes_count

    access_flags:

标志名称
标志值含义
ACC_PUBLIC
0x0001
方法是否为public
ACC_PRIVATE
0x0002
方法是否为private
ACC_PROTECTED0x0004方法是否为protected
ACC_STATIC0x0008方法是否为static
ACC_FINAL0x0010方法是否为final
ACC_SYNCHRONIZED0x0020方法是否为synchronized
ACC_BRIDGE0x0040方法是否为编译器产生的桥接方法
ACC_VARARGS0x0080方法是否接受不定参数
ACC_NATIVE0x0100方法是否为native
ACC_ABSTRACT0x0400方法是否为abstract
ACC_STRICT0x0800方法是否为strictfp
ACC_SYNTHETIC0x1000方法是否为编译器自动产生

在Java语言中,要重载一个方法,处理要和原方法具有相同的名称外,还要有一个和原方法不同的特征签名.特征签名是指一个方法内各个参数在常量池中的字段符号引用的集合.返回值不在特征签名内,所以无法通过返回值不同进行重载.在class文件中,只要描述符不是完全一致的两个方法可以共存,即方法有相同的名称和特征签名,只要返回值不同,可以合法共存.

7) 属性表集合:

属性名称
使用位置含义
Code
方法表Java代码编译成的字节码指令
ConstantValue字段表由final关键字定义的常量值
Deprecated类,方法表,字段表被声明为deprecated的方法和字段
Exceptions
方法表方法抛出的异常列表
EnclosingMethod类文件仅当一个类为局部类或者匿名类才拥有,标示该类所在的外围方法
InnerClasses
类文件内部类列表
LineNumberTableCode属性Java源码的行号和字节码指令的对应关系
LocalVariableTableCode属性方法的局部变量描述
StackMapTableCode属性供新的类型检查验证器检查和处理目标方法的局部变量和操作数栈所需类型是否匹配
Signature
类,方法表,字段表用于支持泛型情况下的方法签名
SourceFile类文件记录源文件名称
SourceDebugExtension类文件用于存储额外的调试信息(例如JSP的调试)
Synthetic类,方法表,字段表标识方法或字段为编译器产生
LocalVariableTypeTable‍‍描述泛型参数化类型
RuntimeVariableAnnoations
类,方法表,字段表用于指明哪些注解运行时可见
RuntimeInvisibleAnnoations类,方法表,字段表用于指明哪些注解运行时不可见
RuntimeVisibleParameterAnnoations方法表
用于指明哪些方法参数的注解运行时可见
RuntimeInvisibleParameterAnnoations方法表
用于指明哪些方法参数的注解运行时不可见
AnnoationDefault
方法表记录注解类元素的默认值
BoostrapMethods
类文件保存invokeDynamic指令引用的引导方法限定符
RuntimeVisibleTypeAnnoations类,方法表,字段表,code属性用于指明哪些类的注解运行时可见
RuntimeInvisibleTypeAnnoations类,方法表,字段表,code属性用于指明哪些类的注解运行时不可见
MethodParameters
方法表用来支持将方法名称编译进class文件并运行时获取
Module
记录module的名称及相关信息(requires,exports,opens,uses,provides)
ModulePackages
记录模块中所有被exports或opens的包
ModuleMainClass用来指定模块的主类
NestHost用于支持嵌套类的反射和访问控制的API,获取自己的宿主类
NestMembers用于支持嵌套类的反射和访问控制的API,宿主类获取自己的内部类

属性表结构

类型
名称数量‍‍
2bitattribute_name_index1
4bitattribute_length1
1bitinfoattribute_length


7.1) Code属性(接口或抽象类的方法可不存在)

类型
名称数量
含义
2bitattribute_name_index1
指向CONSTANT_Utf8_info型常量的索引,值固定为"Code"
4bit
attribute_length1属性值的长度
2bitmax_stack1
操作栈深度的最大值
2bitmax_local1局部变量表所需的存储空间,单位是变量槽(JVM会对变量槽进行重用,因此数量并非所有局部变量和,同时this关键字在参数列表和方法体内会占用一个变量槽)
4bitcode_length1编译后生成的字节码指令的长度(虽然理论值有2^32,但是JVM限制方法不超过65525条字节码指令,超过会拒绝编译)
1bitcodecode_length存储字节码指令的一系列字节流
2bitexception_table_length1

exception_infoexception_tableexception_table_lengthJVM通过异常表而不是通过跳转指令实现异常和finally处理机制
2bit
attributes_count1
attribute_info
attributesattributes_count

7.2) Exceptions属性结构

类型
名称数量含义
2bitattribute_name_index1
4bitattribute_length1
2bitnumber_of_exceptions1表示方法可能抛出number_of_exceptions种受检异常(除RuntimeException外的异常)
2bitexception_index_tablenumber_of_exceptions指向常量池中CONSTANT_Class_info型常量的索引

7.3) LineNumberTable属性结构(非运行必要,可通过-g:none或者-g:lines取消或生存此项信息,不生成的影响就是抛出异常不会显示出错的行号,debug时也无法按源码行设置断点):

类型
名称数量备注
2bitattribute_name_index1
4bitattribute_length1
2bitline_number_table_length1
line_number_infoline_number_tableline_number_table_length包含start_pc(字节码行号)和line_number(源码行号)两个u2类型数据

7.4) LocalVariableTable属性结构(描述栈帧中局部变量表的变量和Java源码中定义的变量之间的关系,非运行必需,通过-g:none或者-g:vars取消或生成这项信息,取消的影响就是引用方法时,参数名称会丢失):

类型
名称数量
2bitattribute_name_index1
4bitattribute_length1
2bit
local_variable_table_length1
local_variable_info
local_variable_tablelocal_variable_table_length

local_variable_info项目结构:

类型
名称数量含义
2bitstart_pc1局部变量生命周期开始的字节码偏移量
2bitlength1作用范围覆盖的长度
2bitname_index1指向常量池CONSTANT_Utf8_info型常量的索引,代表局部变量的名称
2bitdescriptor_index(LocalVariableTypeTable中此项为Signature)1指向常量池CONSTANT_Utf8_info型常量的索引,代表局部变量的描述符(LocalVariableTypeTable此处用于描述泛型)
2bitindex1局部变量表中变量槽的位置

7.5) SourceFile属性结构(非运行必要,可通过-g:none或者-g:source取消或生存此项信息,不生成的影响就是抛出异常不会显示出错代码所属文件名)

类型
名称数量含义
2bitattribute_name_index1
4bitattribute_length1
2bitsourcefile_index1指向常量池CONSTANT_Utf8_info型常量的索引,常量值是源码文件的文件名

7.6) SourceDebugExtension属性结构(一个类最多允许一个SourceDebugExtension属性):

类型
名称数量
2bit
attribute_name_index1
4bit
attribute_length1
1bitdebug_extension[attribute_length](变长UTF-8字符串)1

7.7) ConstantValue属性结构(JVM对非static类型的变量是在实例构造器<init>()方法中进行的;对于final和static修饰的变量如果数据类型是基本类型或者String,生成ConstantValue进行初始化,否则在<cinit>()方法中进行初始化):

类型
名称数量
2bitattribute_name_index1
4bitattribute_length1
2bitconstantvalue_index1

7.8) InnerClasses属性结构(记录内部类和宿主类之间的关联):

类型名称数量
2bit
attribute_name_index1
4bitattribute_length1
2bitnumber_of_classes1
inner_class_info
inner_classesnumber_of_classes

inner_class_info项目结构:

类型
名称数量含义
2bitinner_class_info_index1‍‍指向CONSTANT_Class_info型常量的索引,代表内部类的符号引用‍‍
2bitouter_class_info_index1指向CONSTANT_Class_info型常量的索引,代表宿主类的符号引用
2bitinner_name_index1指向CONSTANT_Utf8_info型常量的索引,代表这个内部类的名称,如果是匿名内部类,值为0
2bitinner_class_access_flags1
内部类的访问标志

inner_class_access_flags

标志名称标志值含义
ACC_PUBLIC0x0001内部类是否为public
ACC_PRIVATE0x0002内部类是否为private
ACC_PROTECTED0x0004内部类是否为protected
ACC_STATIC0x0008内部类是否为static
ACC_FINAL0x0010内部类是否为final
ACC_INTERFACE0x0020内部类是否为接口
ACC_ABSTRACT
0x0400内部类是否为abstract
ACC_SYNTHETIC
0x1000内部类是否由用户代码产生
ACC_ANNOTATION
0x2000内部类是否为一个注解
ACC_ENUM0x4000内部类是否为一个枚举

7.9) Deprecated属性结构(属于标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念):

类型
名称数量
2bitattribute_name_index1
4bitattribute_length(值必须为0x0000)1

7.10) Synthetic属性结构(属于标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念,所有不属于用户代码产生的类、方法以及字段都应设置为Synthetic属性或者ACC_SYNTHETIC标志位的一项,除了实例构造器"<init>()"方法和类构造器"<cinit>()"方法):

类型
名称数量
2bit
attribute_name_index1
4bitattribute_length(值必须为0x0000)1

7.11) StackMapTable属性结构(包含零到多个栈映射帧,每个栈映射帧显示或隐式的代表一个字节码偏移量,用于表示执行到该字节码时局部变量表和操作数栈的验证类型.类型检查验证器会通过检查目标方法的局部变量和操作数栈所需的类型确认一段字节码指令是否符合逻辑约束.一个方法的Code属性最多只能有一个StackMapTable属性):


类型
名称数量
2bitattribute_name_index1
4bitattribute_length1
2bitnumber_of_entries1
stack_map_framestack_map_frame_entriesnumber_of_entries

7.12) Signature属性结构(用于存储类、接口、初始化方法或成员的泛型签名包含的类型变量和参数化类型的泛型签名信息):

类型
名称数量含义
2bitattribute_name_index1
4bitattribute_length1
2bitsignature_index1必须指向常量池CONSTANT_Utf8_info类型的有效索引,表示类签名或者方法类型签名或字段类型签名

7.13) BootstrapMethod属性结构(用于保存invokeDynamic指令引用的引导方法限定符,类文件的属性表中最多只能有一个BootstrapMethod属性,实现意义:lambda表达式和接口默认方法的实现):

类型名称数量
2bitattribute_name_index1
4bitattribute_length1
2bitnum_boostrap_methods1
bootstrap_methodbootstrap_methodsnum_boostrap_methods

bootstrap_method项目结构:

类型
名称数量含义
2bit
boostrap_method_ref1指向常量池CONSTANT_MethodHandle_info结构的有效索引
2bitnum_bootstrap_arguments1成员的数量
2bitboostrap_argumentsnum_bootstrap_arguments必须是CONSTANT_xx_info结构的有效索引

7.14) MethodParameters属性结构(用于程序反射时能获取方法参数名称):

类型
名称数量
2bit
attribute_name_index1
4bitattribute_length1
1bitparameters_count1
parameter
parametersparameters_count

parameter项目结构:


类型
名称数量含义
2bit
name_index1指向常量池CONSTANT_Utf8_info结构的有效索引
2bitaccess_flags1

0x0010(ACC_FINAL):表示参数被final修饰;

0x1000(ACC_SYNTHETIC):表示参数是编译器自动生成的;

0x8000(ACC_MANDATED):表示参数是源文件中隐式定义的,比如this关键字

文章转载自没意思先生,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论