java class 文件通常是由java源文件(.java)通过编译生成的。一个class文件只能表示一个类或接口。
class文件格式不很复杂。最前面的8个bytes与class格式有关而与具体的类或接口的无关,其中前面的4个bytes为0xCAFEBABE, 是class文件的标记; 接着4个bytes是class文件的版本,如1.5, 2.0等; 下面的2个bytes来说明常量池入口的个数, 接着就的常量池了。顾名思义常量池就是一个集中存储常量的地方, 这些常量主要是类、 方法和属性的名称,boolean, char, short, int, long, float, double 和 string 的值。
class文件中余下的内容就很好理解了, 可以对比一个具体的java文件, 比如说
public class A extends B implements C,D{ int i; public void showInfo(){} class E{ } }
首先是一个2个bytes 的mask, 表示该类与接口的访问属性,如,是否为public, final, abstract, interface。接着看到的是一个2个bytes的指向常量池的索引, 说明该类或接口的名称, 接下来的2个bytes仍是指向常量池的索引,其值会因该文件表示的类型的的不同革命而不同。如果该class文件表示的是类, 则说明该类的直接父类的名称, 如表示的是Object类, 该值为0, 如果表示的是一个接口, 则其值指向Object类。接着的2个bytes说明该类实现或的该接口的扩展的接口的个数n,接下来的2n个bytes表示n个指向常量池的索引,表示实现的n个接口的名称。
前面的这些只说明了类的一些基本信息, 类或接口名称是什么, 父类叫什么, 实现或扩展的哪些接口,并没有包含该类或接口新声明了几个属性, 几个方法, 这些属性和方法是什么的, 以及其它的一些信息, 比如有没有内部类等等。这些信息记录的余下的class文件中。
首先2个bytes,说明该类或接口中声明的属性的个数m(不包含从父类或接口继承来的), 下面m个field结构, 这个结构不同C/C++中的结构, 其大小是变化的。结构中包含这个属性的访问限定符, 类型, 名称以及可能的一些附加信息。再接着就是该类或接口声明的方法的个数k(同样不包括从父类或接口继承来的),接着就是k个method 结构,该结构详细的说明了的方法的信息。如, 方法的访问限定符, 名称, 参数及返回值类型, 如果该方法不是native或abstract, 还必须包含实现该方法的jvm 指令, 同时也有可能包含一些方法的调试信息。class文件的最后是类或接口的一些附加的信息, 主要是关于内部类的。
下面附加java虚拟机规范中对class文件结构的描述(un 表示n 个字节):
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]; }