分类:
2008-10-28 18:22:45
一、什么是类文件
类文件是Java程序的二进制表示形式。每一个类文件代表一个类或者接口。不可能在一个类文件中放入多个类或者接口。这样就使得无论类文件是在哪一种平台上生成,都可以在任何主机上执行。
虽然类文件是Java体系结构的一部分,但是他并不是与Java语言不可分的。你可以将其他语言的程序编译为类文件,也可以将Java程序文件编译为其他二进制形式。
Java类文件是一个基于8-bit字节的二进制流。数据块顺序的、无分割符的、big-endian的形式。
二、类文件的内容
Java的类文件中包含了所有Java虚拟机所需要的关于类和接口的信息。所有类文件中的信息都以以下的四种基本类型的:
Table 6-1. Class file "primitive types"
u1 a single unsigned byte
u2 two unsigned bytes
u4 four unsigned bytes
u8 eight unsigned bytes
类文件中的主要部分以表6-2的顺序存储:
Table 6-2. Format of a ClassFile Table
Type& #9;Name Count
u4 magic 1
u2 minor_version 1
u2 major_version 1
u2 constant_pool_count 1
cp_info constant_pool constant_pool_count-1
u2 access_flags 1
u2 this_class 1
u2 super_class 1
u2 interfaces_count 1
u2 interfaces interfaces_count
u2 fields_count 1
field_info fields fields_count
u2 methods_count 1
method_info methods methods_count
u2 attributes_count 1
attribute_info attributes attributes_count
1、魔术编码(magic)
每一个Java类文件的开头四个字节都是魔术编码(OxCAFEBABE)。通过魔术编码可以很容易识别类文件。
2、副版本号和主版本号(minor_version and major_version)
剩下的四个字节是副版本号和主版本号。但Java技术在进化时,一些新的特性可能会被加入到类文件中。每一次类文件格式的变化,都会相应的改变版本号。虚 拟机通过版本号来识别自己能够处理的类文件。Java虚拟机往往只能处理一个给定的主版本号和其下的一些副版本号。虚拟机必须拒绝那些不再处理范围内的类 文件。
3、常量个数和常量池(constant_pool_count and constant_pool)
接下来的就是常量池,常量池中包含了哪些被类或者接口访问过的常量,比如:字符串,常量(final variable values),类名,方法名。常量池作为一个列表存储。列表中常量的个数就是之前保存的“constant_pool_count”。
很多常量池中的常量都引用了常量池中的其他常量,那些引用常量池常量的引用最终也会转换为对常量池中常量的直接引用。虽然常量列表中的索引是从1开始的,但是常量个数还是包含了0,比如一个常量列表中有15个常量,那么它的常量个数就为16。
每一个常量开头都会有一个标志,以表示他的类型。当虚拟机读取这个标志时,就会知道这个常量的具体类型了。表6-3列举了这些标志:
Table 6-3. Constant pool tags
Entry Type Tag Value Description
CONSTANT_Utf8 1 A UTF-8 encoded Unicode string
CONSTANT_Integer 3 An int literal value
CONSTANT_Float 4 A float literal value
CONSTANT_Long 5 A long literal value
CONSTANT_Double 6 A double literal value
CONSTANT_Class 7 A symbolic reference to a class or interface
CONSTANT_String 8 A String literal value
CONSTANT_Fieldref 9 A symbolic reference to a field
CONSTANT_Methodref 10 A symbolic reference to a method declared in a class
CONSTANT_InterfaceMethodref 11 A symbolic reference to a method declared in an interface
CONSTANT_NameAndType 12 Part of a symbolic reference to a field or method
表6-3中的每一个标志都会有一个相应的表格,用来描述这个标志的所表示的一些详细信息,这些对应的标志都会以标志名+_INFO来结尾。比如CONSTANT_CLASS标志对应的就是CONSTANT_CLASS_INFO。
常量池在程序的动态链接中扮演了很重要的角色。除了上边所说的各种常量值以外,常量池中包含了一下三种符号引用:类和接口的全名,字段名和描述符,方法名 和描述符。一个字段是一个类或者接口中的实例或者类变量,字段描述符是字段的类型。方法的描述符是方法和返回值和参数的个数、顺序和类型。在虚拟机将这个 类或者接口链接到其他类或者接口时用到这些全名。因为类文件不包含任何关于内存结构的信息,所以这个链接只能以符号引用的形式存在。虚拟机在执行时将这些 符号引用转换为实际的地址。具体的信息参见第八章“The Linking Model”。
4、访问标志(access_flags)
紧接在常量池后面的两个字节就是访问标志,表示这个类或者接口的几方面信息,他有如下几种值:
Table 6-4. Flag bits in the access_flags item of ClassFile tables
Flag Name Value Meaning if Set Set By
ACC_PUBLIC 0x0001 Type is public Classes and interfaces
ACC_FINAL 0x0010 Class is final Classes only
ACC_SUPER 0x0020 Use new invokespecial semanticsClasses and interfaces
ACC_INTERFACE 0x0200 Type is an interface, not a class All interfaces, no classes
ACC_ABSTRACT 0x0400 Type is abstract All interfaces, some classes
ACC_SUPER标志是为了兼容以前SUN的老式的编译器。所有没有使用的访问标志,必须设置为0。
5、类名(this_class)
接下来的两个字节保存了一个常量池的索引。这个常量池中的实体必须是CONSTANT_CLSS_INTO类型的,他包含了标志和名字索引。标志就是 CONSTATN_CLASS,那个名字索引应该是一个保存了这个类或者接口全名的CONSTANT_UTF8_INFO类型的索引。
6、父类(super_class)
this_class之后的就是两个字节的super_class,他也是一个常量池的索引,其中保存了父类的全名,处理this_class一样。当父 类是java.lang.Object时,super_class都应该是0。对于接口super_class都是0。
7、(interfaces_count and interfaces)
interfaces_count中保存了父接口的个数,interfaces中以数组形式保存了一些常量池的索引。每一个索引都指向了一个 CONSTANT_CLASS_INFO的常量,其中保存了每一个父接口的全名。这个数组的顺序就是父接口出现在在implements、extends 语句中从左到右的顺序。
8、(fields_count and fields)
字段被保存在一个field_info的列表中,fields_count是这个列表的长度。Field_info列表中保存的只是类或者接口中的申明的变量,从父类或者父接口中继承的字段不保存在这里。
每一个field_info表中的一条都描述了一个字段的信息,包括:字段名,描述符,访问权限。如果一个字段被申明为final,那么这个字段的信息即会保存在field_info表中,也会保存在常量池中。
9、(methods_count and methods)
方法的信息都保存在method_info表中,mehtods_count是表的长度。Method_info表中只保存类或者接口中申明的方法,不保存从父类或者接口中继承的方法。
Method_info 表中保存了方法名和描述符(返回值和参数类型)。如果不是抽象方法,还会保存用于堆栈的大小(保存本地变量用的)、操作数堆栈的最大值、捕捉的异常列表、 方法的字节码、可选的行号和本地变量表。如果方法抛出一些被检查的异常,method_info还会包含一个被检查异常的列表。
10、(attributes_count and attributes)
类文件中最后的就是属性个数和atribute_info列表。Atribute_info表中保存了一些指向常量池中constant_utf8_info的索引,其中保存了属性的名字。Java虚拟机规范中定义了两种类型的属性:源代码和内部类。
[1]