魔数
每个class文件的头4个字节称为魔数(Magic Number),其值为:0xCAFEBASE,它的唯一作用是用于确定这个文件是否为一个能被虚拟机接受的class文件。使用魔数而不是扩展名来进行识别主要是基于安全的考虑,因为文件的扩展名可以随意地被改动。
版本号
紧接着魔的4个字节存储的是class文件的版本号:第5和第6个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)。java的版本是从45开始的,JDK1.1之后的每个JDK大版本发布主版本号上加1(JDK1.0-1.1使用了45.0-45.3的版本号),高版本的JDK能向下兼容以前版本的class文件,但不能运行以后版本的class文件,即使文件格式并未发生变化。JDK1.2对应主版本号为46,JDK1.3为47,依此类推。
常量池
紧接着主次版本号之后的是常量池入口,常量池是class文件结构中与其它项目关联最多的数据类型,也是占用class文件空间最大的数据项目之一,同时它还是class文件中第一个出现的表类型数据项目。
由于常量池中常量的数据是不固定的,所以在常量池的入口需要放置一荐u2类型的数据,代表常量池容量计算值(constant_pool_count)。与Java语言习惯不一样的是,这个容量计数是从1而不是0开始的。将第0项常量出来的目的是为了满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项目”的意思。class文件结构中只有常量池的容量计数是从1开始,对于其它集合类型,包括接口索引集合,字段表集合,方法表集合的容量计算都是从0开始的。
常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。字面量比较接近于Java语言层面的常量概念,如文本字符串,被声明为final的常量值等。而符号引用则属性编译原理方面的概念,包含了下面三类常量:
a.类和接口的全限定名(Fully Qualified Name)
b.字段的名称和描述符(Descriptor)
c.方法的名称和描述符
常量池中的每一项常量都是一个表,共有11种结构各不相同的表结构数据,这11种表都有一个共同的特点,就是表开始的第一位是一个u1类型的标志位,代表当前这个常量属性哪种常量类型,11种常量类型具体含义如下:
各常量项结构: