Class文件结构
2020-08-29 20:12:21 37 举报
完整的Class文件结构
作者其他创作
大纲/内容
access_flags
u2
方法的描述符,对常量池项的引用
u4
属性名索引指向常量中utf8的固定值\"ConstantValue\"
number_of_exception:可能抛出异常数
attribute_length:该属性的整个长度
魔术作用:判断该文件是否可被JVM接受格式:0xCAFFBABE(两个16进制数占一个字节,刚好为u4 四个字节)
标记
descriptor_index
表示常量池个数(需要减一)
属性名索引指向常量中utf8的固定值\"Exceptions\"
字段的简单名称,对常量池项的引用
u0
CONSTANT_Utf8_info
class文件结构
u1 * length
u1
属性名索引指向常量中utf8的固定值\"LocalVaribaleTable\"
注意:字段表不会保存从父类或者父接口继承的字段
类索引:确定该类的全限定类名
attributes_count
指向一个CONSTANT_Utf8_info
constant_pool
minor_version
字段访问标志,和类的访问标志类似(public staic final...)
minor_version:次版本号major_version:主版本号说明:每次大更新主版本号加1,小更新次版本号加1,JVM可以接受小于或等于其版本号的.class文件,是向下兼容的。注意:此版本号在jdk1.2前用到过,之后直到jdk12一直都为0
每一种受查异常使用一个exception_index_table项表示;exception_index_table是一个指向常量池中CONSTANT_Class_info型常量的索引,代表了该受查异常的类型
start_pc和length属性分别代表了这个局部变量的生命周期开始的字节码偏移量及其作用范围覆盖的长度,两者结合起来就是这个局部变量在字节码之中的作用域范围。
info
exception_length:异常表长度exception_info:异常表 从start_pc 到 end_pc,出现了catch_type异常,跳转到handler_pc进行处理。说明:异常表用于当代码中出现某些个异常时会跳转道指定位置进行从处理
attributes_info
我们分析其中的几个
表示类或接口的符号引用
字段表的结构
方法的简单名称,对常量池项的引用
interface_count
接口索引集合:如果该类没有实现接口,interface_count为0x0000,如果实现了interfaces中接口按照声明时从左到右的顺序排列,这些排列的接口索引指向常量池中的CONSTANT_Class_info
属性名索引指向常量中utf8的固定值\"LineNumberTable\"
常量池中一些符号引用可能会指向它,如com.wang.Person
我们可以通过不同编译器将各种语言源代码翻译成同一种文件格式的.class文件,然后通过JVM实现跨平台。即一次编译,到处运行。注意:不同的操作系统或硬件系统我们都有对应的JVM,我们这里唯一没有一点变化的是.class文件
具体的数值
。。。。。。
用描述符来描述方法时,按照先参数列表、后返回值的顺序描述,参数列表按照参数的严格顺序放在一组小括号“()”之内。如方法void inc()的描述符为“()V”,方法java.lang.String toString()的描述符为“()Ljava/lang/String;”,方法intindexOf(char[]source,int sourceOffset,int sourceCount,char[]target,inttargetOffset,int targetCount,int fromIndex)的描述符为“([CII[CIII)I”。
区别全限定名:com/wang/Person简单名称:方法inc(),简单名称inc描述符:字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值
line_number_table是一个数量为line_number_table_length、类型为line_number_info的集合,line_number_info表包含start_pc和line_number两个u2类型的数据项,前者是字节码行号,后者是Java源码行号。
字面量
属性集合:用于描述字段或方法的一些个专有信息。如Code属性表示方法的具体执行代码的字节码,ConstantValue表示又final修饰的常量等等
它们各自指向一个类型为CONSTANT_Class_info的类描述符常量
常量池:1.常量池的项是从1开始的。2.常量池主要分为字面量和符号引用字面量:一些固定的值(如字符串,数值,final修饰的)符号引用:包名,类和接口全限定名,字段和访问名称或描述符号,方法类型和句柄,动态调用点和动态常量关于符号引用:class文件在编译时,一些个方法字段等是不知道在内存中具体位置的,所有我们使用符号引用来代替其,当class文件加载时,在解析阶段会将符号引用换成直接引用此时,才知道真正的内存地址
CONSTANT_Class_info
属性表集合,用于存储一些额外的信
数据结构中可以看出ConstantValue属性是一个定长属性,它的attribute_length数据项值必须固定为2。
LineNumberTable属性用于描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系。它并不是运行时必需的属性,但默认会生成到Class文件之中,可以在Javac中使用-g:none或-g:lines选项来取消或要求生成这项信息。如果选择不生成LineNumberTable属性,对程序运行产生的最主要影响就是当抛出异常时,堆栈中将不会显示出错的行号,并且在调试程序的时候,也无法按照源码行来设置断点。
方法表结构
这里的Exceptions属性是在方法表中与Code属性平级的一项属性,读者不要与前面刚刚讲解完的异常表产生混淆。Exceptions属性的作用是列举出方法中可能抛出的受查异常(Checked Excepitons),也就是方法描述时在throws关键字后面列举的异常。
magic
u2 *u2
标志
父类索引:确定该类的父类的全限定类名
fields_count
Exceptions属性
fields
指向字符串字面量的索引
constantvalue_index数据项代表了常量池中一个字面量常量的引用,根据字段类型的不同,字面量可以是CONSTANT_Long_info、CONSTANT_Float_info、CONSTANT_Double_info、CONSTANT_Integer_info和CONSTANT_String_info常量中的一种。
长度为length字节的字符串
index是这个局部变量在栈帧的局部变量表中变量槽的位置。当这个变量数据类型是64位类型时(double和long),它占用的变量槽为index和index+1两个。
methods
LineNumberTable属性
ConstantValue属性
长度
attribute_length:指示了属性值的长度,由于属性名称索引与属性长度一共为6个字节,所以属性值的长度固定为整个属性表长度减去6个字节。
code_length:代表字节码长度(一般实际不超过2^16个字节,除特殊情况如JSP文件翻译成字节码时)code:用于存储字节码指令的一系列字节流。说明:每个指令就是一个u1类型的单字节,并且可以知道这条指令后面是否需要跟随参数,以及后续的参数应当如何解析。我们知道一个u1数据类型的取值范围为0x00~0xFF,对应十进制的0~255,也就是一共可以表达256条指令。
interfaces
constant_pool_count
name_index
注意:1.class文件是以八字节作为基本的流来处理,并且个字段之间不存在任何空隙。2.class文件只有两个类型无符号型和表(u 或 _info)
u1 * u4
CONSTANT_String_info
其中local_variable_info项目代表了一个栈帧与源码中的局部变量的关联
UTF-8编码字符串
super_class
LocalVariableTable属性
max_locals:代表了局部变量表所需的存储空间。max_locals的单位是变量槽(Slot),变量槽是虚拟机为局部变量分配内存所使用的最小单位。对于byte、char、float、int、short、boolean和returnAddress等长度不超过32位的数据类型,每个局部变量占用一个变量槽,而double和long这两种64位的数据类型则需要两个变量槽来存放。
注意:与字段表集合相对应地,如果父类方法在子类中没有被重写(Override),方法表集合中就不会出现来自父类的方法信息。但同样地,有可能会出现由编译器自动添加的方法,最常见的便是类构造器“<clinit>()”方法和实例构造器“<init>()”方法
描述符
max_stack:代表了操作数栈(Operand Stack)深度的最大值。在方法执行的任意时刻,操作数栈都不会超过这个深度。虚拟机运行的时候需要根据这个值来分配栈帧(Stack Frame)中的操作栈深度
在Java语言中,要重载(Overload)一个方法,除了要与原方法具有相同的简单名称之外,还要求必须拥有一个与原方法不同的特征签名[插图]。特征签名是指一个方法中各个参数在常量池中的字段符号引用的集合,也正是因为返回值不会包含在特征签名之中,所以Java语言里面是无法仅仅依靠返回值的不同来对一个已有方法进行重载的。但是在Class文件格式之中,特征签名的范围明显要更大一些,只要描述符不是完全一致的两个方法就可以共存。也就是说,如果两个方法有相同的名称和特征签名,但返回值不同,那么也是可以合法共存于同一个Class文件中的。
major_version
attributes
attribute_length: 整个属性的长度
对于数组类型,每一维度将使用一个前置的“[”字符来描述,如一个定义为“java.lang.String[][]”类型的二维数组将被记录成“[[Ljava/lang/String;”,一个整型数组“int[]”将被记录成“[I”。
访问标记:来表示该class是类还是接口,是否为public等类型(16位)
CONSTANT_Integer_info
methods_count
name_index和descriptor_index都是指向常量池中CONSTANT_Utf8_info型常量的索引,分别代表了局部变量的名称以及这个局部变量的描述符。
ConstantValue属性的作用是通知虚拟机自动为静态变量赋值。只有被static关键字修饰的变量(类变量)才可以使用这项属性。如果同时使用final和static来修饰一个变量(按照习惯,这里称“常量”更贴切),并且这个变量的数据类型是基本类型或者java.lang.String的话,就将会生成ConstantValue属性来进行初始化;如果这个变量没有被final修饰,或者并非基本类型及字符串,则将会选择在<clinit>()方法中进行初始化。
Code属性
local_variable_info
方法里的Java代码,经过Javac编译器编译成字节码指令之后,存放在方法属性表集合中一个名为“Code”的属性里面,属性表作为Class文件格式中最具扩展性的一种数据项目
this_class
u1 * u2
fields:字段表。用来描述接口或者类中声明的类变量或者实例变量fields_count:字段数
0 条评论
下一页