读书人

Java虚拟机学习札记(2)-Class文件

发布时间: 2012-10-28 09:54:44 作者: rapoo

Java虚拟机学习笔记(2)--Class文件
Java Class File :
内容、常量池的结构及其格式等

1. What?
class文件是对jvm能接受的有效程序格式定义
java class 文件是8位字节的二进制流。数据项按顺序存储在class 文件中,相邻项之间没间隔,这样的class文件更紧凑

对于数据长度不定的项,在class文件中,一般先是项的大小,然后是项的数量

2.class文件的内容
(1)magic(魔数):
class file的前4个字节被称为他的magic:0xCAFEBABE,vm通过magic来识别是否是class文件

(2)minor_version和major_version:
4个字节包括主、次版本,对vm来说版本确定了格式,只有给出主次版本,并使vm通过其验证后方可执行

编译javac时可通过加 -target xxx来指定特定的版本

(3)constant_pool_count和constant_pool
常量池中存储了文字字符串、final变量值、类名和方法名的常量

常量池入口都是从一个长度为一字节的标志开始,这个标志指出类列表中该位置的常量类型

每个标志都有一个对应的表,表明是在标识名后加上_info后缀来产生的

动态连接的java程序中,常量池非常重要,除了字面常量外还可以容纳:类和接口的全限名、字段名称和描述符、方法名称和描述符。

因为class文件没有内存布局的信息,所以vm需要从常量池中获得符号引用,然后在运行时解析引用项的实际地址

(4) access_flags
两个字节的access_flags展示了文件定义中的类或接口的几段信息(包括是类还是接口?是什么修饰符?final?abstract?)

flag未使用的位必须的由编译器置为0,而vm会忽略他

(5) this_class
this_class是对一个常量池的索引,入口必须为CONSTANT_Class_info表,通过这表tag后的name_index指针可以找到一个容纳了类或接口全限名CONSTANT_utf8_info的入口

(6) super_class
super_class指向超类的CONSTANT_Class_info表,对于没有超类的Object super_class 为0

(8) interfaces_count 和 interfaces
count顾名思义就是计数,而后面的interfaces每个都是指向CONSTANT_Class_info的表指针

(9)fields_count 和 fields
count也是计数,fields是不同长度的field_info表序列(期中不列出超类或父接口继承而来的字段)

但有可能有java中没描述的字段,比如内部类的对外引用

对于申明为final的字段,field_info会有常量信息,或者放在field_info所指向的常量池中

(10) methods_count 和 methods
count计数,之后是method_info的列表(方法名,描述符[参数类型、返回值类型],如果不是抽象不是本地的,那么method_info有局部变量所需的栈空间长度、异常表、字节码序列以及可选的行数和局部变量表),注意方法不包括在父类和接口定义的方法。

(11) attributes_count 和 attributes
count还是计数,atrributes中指向attribute_info表,表的第一项是指向常量池CONSTANT_UTF8_info的索引,期中给出了表的属性名称

atrribute不止有class file级有,其他的比如field_info\method_info中也有相关的attribute信息


3. 特殊字符串
常量池容纳的符号引用包括三种特殊字符串:全限定名、简单名称和描述符。

所有符号引用-类或接口的全限定名、
字段的符号引用 -> +简单字段名 +字段描述符
方法的符号引用 -> +简单方法名 +方法描述符

(1)全限定名:
全限名在class文件中一般用斜线替换了

(2)简单名称:
字段名和方法名以简单名称(非全限定名)形式出现在常量池入口中。String toString() -> toString

(3)描述符:
指向字段和方法的符号引用还包含描述字符串

字段描述符:包括字段的类型
方法描述符:返回值、方法参数的数量、类型以及顺序

注意:实列方法没有包含作为第一个参数的this参数,但调实列方法的虚拟机指令都会隐式的传递this参数给他

4. 常量池
CONSTANT_UTF8_info UTF\CONSTANT_Integer_info\CONSTANT_Float_info\
CONSTANT_Long_info\CONSTANT_Double_info\CONSTANT_Class_info\
CONSTANT_String_info\CONSTANT_Fieldref_info\CONSTANT_Methodref_info\
CONSTANT_InterfaceMethodref_info\CONSTANT_NameAndType_info

5. 字段
类或接口中申明的每个字段都有一个名为field_info的可变长表进行描述,在表中不允许存在字段描述和字段名都重复的情况,所以,class文件中可能出现名字相同,描述不同的情况,而这种情况在java中是不会出现的

access_flag 中有关于字段修饰符的信息

6. 方法
在类或接口中申明的或由编译器生成的每个方法都有一个method_info可变长表进行描述,一样也不允许有方法名称和描述都相同的情况,so只有方法返回值不通在class文件中是允许的。

编译器生成的方法有<init>----实列构造方法,<clinit>----类和接口初始话方法

access_flag 中有关于方法修饰符的信息,值得注意的是<clinit>会被申明为strictFP,所以他只可以被VM调用

7. 属性
属性可以出现多个地方,VM规定了9种属性。为了解释class,必须能解释Code\ConstantValue\Exception
为了支持Java1.2+必须能识别InnerClass和Synthetic属性


名称 使用 描述
Code method_info 方法的字节码
ConstantValue field_info final的值
Exceptions method_info 方法抛出的被检查的异常
InnerClasses ClassFile 内部类
LineNumberTable Code_attribute 字节码和源码行数的对照
LocalVariableTable Code_attribute 方法用到的局部变量
SourceFile ClassFile 源文件名
Synthetic field_info, method_info 表示字段或者方法是有编译器产生

每种属性都有attribute_name_index指向包括属性名的CONSTANT_UTF8_info常量池,之后有attribute_length是去去掉开始6字节后的长度,通过length可以控制跳过无法识别的属性。最后就是主体info

1)Code属性
Code_attribute 表定义了方法的字节序列和其他信息,不是抽象和本地的method_info中都有一个Code

attribute_name_index\attribute_length\max_stack\max_locals\
code_length\code\exception_table_length\exception_table\
attribute_count\attributes
exception_info(start_pc\end_pc\handler_pc\catch_type)

2)CONSTANTValue属性
在包含CONSTANT_Value属性的字段必须设置ACC_STATIC标志,并且可能要设置ACC_FINAL标志

3)Deprecated
可能用于field_info\method_info\ClassFile内表示已淘汰

4)Exceptions
列出了method_info中的方法可能会抛出的异常

5)InnerClasses
如果类或接口的常量池包含任何内嵌类型的CONSTANT_Class_info入口,那么此类或接口的class文件必须包含一个InnerClass_attribute表,此表存在ClassFile的attributes项中。

这个表中的classes项给出了一个成员为inner_class_info的数组(inner_class_info_index\outer_class_info_index)

只要classFile的常量池对其他CONSTANT_Class_info有引用,就会有inner_class_info,inner_class_info_index对内嵌的(非匿名)成员引用,或者outer_class_info_index对外部的引用,如果没有外部(外部为包)则为0

6)LineNumberTable
建立了方法字节码偏移量和源代码行之间的映射关系(name_index+line_number_table_length+line_number_table[startpc+linenumber])

7)LocalVariableTable
方法中栈帧中局部变量部分内容和源码局部变量的名字和描述符之间的映射[startpc->name+descriptor]

8)SourceFile属性
只有一个SourceFile_attribute表。。。

9)Synthetic
指明是由编译器产生的字段、方法或类型

读书人网 >编程

热点推荐