java class 文件是对Java程序二进制文件格式的精确定义。每一个Java class文件都对一个Java类或者Java接口做出了全面描述。一个class文件中只能包含一个类或者接口。无论Java class文件在何种系统上产生,无论虚拟机在何种操作系统上运行,对Java class文件的精确定义使得所有Java虚拟机都能够正确地读取和解释所有Java class文件。
尽管class文件与java语言结构相关,但它并不一定必须与Java程序相关。
如上图所示:可以使用其他语言来编写程序,然后将其编译为class文件,或者把Java程序编译为另一种不同的二进制文件格式。实际上,Java class文件的形式能够表示Java源代码中无法表达的有效程序,然而,绝大多数Java开发者几乎都会选择使用class文件作为传递给虚拟机的首要方式。Java class文件是八位字节的二进制流。数据项按顺序存储在class文件中,相邻的项之间没有任何间隔,这样可以使得class文件紧凑。占据多个字节空间的想按照高位在前的顺序分为几个连续的字节存放。
和java的类可以包含多个不同的字段、方法、方法参数、局部变量等一样,Java class文件也能够包含许多不同大小的项。在class文件中,可变长度项的大小和长度位于其实际数据执之前。这个特性使得class文件流可以从头到尾被顺序解析,首先读出项的大小,然后读出项的数据。
Class文件的内容是什么?
Java class文件中包含了Java虚拟机所需知道的,关于类或接口的所有信息。
A class file consists of a single ClassFile structure:
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];
}
备注:u1 a single unsigned byte
u2 two unsigned bytes
u4 four unsigned bytes
u8 eight unsigned bytes
Magic Number: 0xCAFEBABE
Version of Class File Format: the minor and major versions of the class file
Constant Pool: Pool of constants for the class
Access Flags: for example whether the class is abstract, static, etc
This Class: The name of the current class
Super Class: The name of the super class
Interfaces: Any interfaces in the class
Fields: Any fields in the class
Methods: Any methods in the class
Attributes: Any attributes of the class (for example the name of the sourcefile, etc)
ClassFile表中各项简介如下:
(1) magic(魔数)
每个Java class文件的前四个字节被称为他的魔数(magic number):0xCAFEBABE。魔数的作用在于。可以轻松的分辨出Java class文件和非Java class文件,如果一个文件不是以0xCAFEBABE开头,那它肯定不是java class文件。文件格式定义者能够自由选择魔数,前途是这个选中的魔数值没有被广泛应用。当java还被称为“Oak”的时候,这个魔数就已经确定下来了。依照Patrick Naughton(最初Java开发小组的关键成员)的说法:“早在Java第一次作为该语言的名字发布前,我们就寻找一些好玩的、唯一的、容易记忆的东西。选择0xCAFEBABE只不过是一个巧合,他象征着著名的咖啡品牌Peet's Coffee中最受欢迎的baristsa(一种咖啡的名称),他预示着Java这个名字的出现”
(2)minor_version和major_version
class文件的下面4个字节包含了主、次版本号。随着Java技术的发展,Java class文件格式可能会加入新特性。class文件格式一旦发生变化,版本号也会随之变化。对于Java虚拟机来说,版本号确定了特定的class文件格式,通常只有给定主版本号和一系列次版本号后,Java虚拟机才能够读取class文件。如果class文件的版本号超出了Java虚拟机所能处理的有效范围,Java虚拟机将不会处理该class文件。
在Sun的JDK1.0.2发布版中,Java虚拟经济实现支持从45.0(主版本号为45,次版本号为0)到45.3的class文件格式。在所有JDK1.1发布版本中虚拟机都能够支持版本从450.到45.65535的class文件格式。在Sun的1.2版本的SDK中,虚拟机能够支持从版本45.0到46.0的class文件格式。
(3)constant_pool_count和constant_pool
在class文件中,魔数和版本号后面的是常量池。在其它JVM的介绍中提到的http://boy00fly.iteye.com/blog/1095263,常量池中包含了与文件中类和接口相关的常量。常量池中存储了诸如文字字符串、final变量值、类名和方法名的常量。Java虚拟机把常量池组织为入口列表的形式。在实际列表constant_pool之前,是入口在列表中的计数constant_pool_count.
常量池中的许多入口都指向其他的常量池入口,而class文件中紧随这常量池的许多条目也会指向常量池中的入口。在整个class文件中,指示常量池入口在常量池列表中位置的整数索引都指向这些这些常量池入口。列表中的第一项索引值为1,第二项索引值为2,一次类推。尽管constant_pool列表中没有索引值为0的入口,但缺失的这一入口也被constant_pool_count计数在内。例如:当constant_pool中有14项(索引值从1到14)时,constant_pool_count的值为15。
每个常量池入口都从一个长度为一个字节的标志开始,这个标志指出了列表中该位置的常量类型。一旦java虚拟机获取并解析这个标志,Java虚拟机就会知道标志后的常量类型时什么。
Entry Type Tag ValueDescription
CONSTANT_Utf8 1A UTF-8 encoded Unicode string
CONSTANT_Integer 3An int literal value
CONSTANT_Float 4A float literal value
CONSTANT_Long 5A long literal value
CONSTANT_Double 6A double literal value
CONSTANT_Class 7A symbolic reference to a class or interface
CONSTANT_String 8A String literal value
CONSTANT_Fieldref 9 A symbolic reference to a field
CONSTANT_Methodref 10A symbolic reference to a method declared in a class
CONSTANT_InterfaceMethodref 11 A symbolic reference to a method declared in an interface
CONSTANT_NameAndType 12Part of a symbolic reference to a field or method
上面的每一个标志都有一个相对应的表,表明通过在标志名后加上"_info"后最来产生。例如:对应于CONSTANT_Class标志的表名为CONSTANT_Class_info,表名为CONSTANT_Utf8_info的表中存储着Unicode字符串的压缩形式。对应于各种不同的常量池入口的表,在后续章节中再阐述。
在动态连接的Java程序中,常量池充当了十分重要的角色。除了字面常量(或者说直接量)以外,常量池还可以容纳下面几种符号引用;
1.类和接口的全限定名
2.字段的名称和描述符
3.方法的名称和描述符
字段是类或接口的实例变量或者类变量。字段的描述符是一个指示字段的类型的字符串。
方法的描述符也是一个字符串,该字符串指示方法的返回值和参数的数量、顺序和类型。
在运行时,Java虚拟机使用常量池的全限定名、方法和字段的描述符,把当前类或接口中的代码与其他类或接口中的代码连接起来。
由于class文件并不包含其内部组件最终内存布局的信息,因此类、字段和方法并不能被class文件中的字节码直接引用。
java虚拟机从常量池获得符号引用,然后再运行时解析引用项的实际地址。例如,用来调用方法的字节码指令把一个符号引用的常量池所有传给所调用的方法。
(4)access_flags
紧接常量池后的两个字节称为access_flags,他展示了文件中定义的类或接口的几段信息。例如,访问标志指明文件中丁定义的是类还是接口;访问表示还定义了在类或接口的声明中使用了哪种修饰符;类和接口是抽象的,还是公共的;类的类型可以为final,而final类不可能是抽象的;接口不能为final类型。
(5)this_class
接下来的两个字节为this_class项,他是一个对常量池的索引。在this_class位置的常量池入口必须为CONSTANT_Class_info表。.....
(6)super_class
在class文件中,紧接在this_class之后的是super_class项,他是一个两个字节的常量池索引。在super_class位置的常量池入口是一个指向该类超类全限定名CONSTANT_Class_info.
(7) interface_count和interface
紧接着super_class的是interface_count。此项的含义为:在文件中由该类直接实现或者由接口扩展的父接口的数量。在这个计数的后面,是名为interface的数组,他包含了对每个由该类或者接口直接实现的父接口的常量池索引。
(8) fields_count和fields
紧接在interfaces后面的是对在该类或接口中所声明的字段的描述。首先是名为fields_count的计数,他是类变量和实例变量的字段的数量总和。
在这个技术后面的是不同长度的field_info表的序列。
field的结构具有以下格式:
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
(9)methods_count和methods
紧接在fields后面的是对在该类或接口中所声明的方法的描述。
method的结构具有以下格式:
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
(10)attributes_count和attributes
class文件中最后的部分是属性(attribute),他给出了在该文件中类或接口锁定义的属性的基本信息。
attribute的结构具有以下格式:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}