废话少说,先贴一段代码
package com.study;
public class MyTest {
int a = 1;
public void setA(int a) {
this.a = a;
}
public int getA() {
return a;
}
}
下图为使用十六进制编辑器打开以上代码编译后的Class文件得到的结果:
每个Class文件的头4个字节称为魔数,它的作用是确定这个文件是否为一个能被虚拟机所接受的Class文件。
魔数值为固定值:0xCAFEBABE。
魔数之后的4个字节为版本信息,前两个字节表示minor version(次版本号),后两个字节表示major version(主版本号)。这里的版本号为00 00 00 34,换算成十进制表示次版本号为0,主版本号为52。所以该文件版本号为:1.8.0。
紧接着主版本号之后的就是常量池入口。一个java类中定义的很多信息都是由常量池来维护和描述的,可以将常量池看做是Class文件的资源仓库,比如说java类中定义的方法与变量信息,都是存储在常量池中。常量池中主要存储两类常量:字面与符号引用。字面量如文本字符串,Java中声明为final的常量值等,而符号引用如类和接口的全局限定名,字段名称和描述符,方法的命名成和描述符等。
常量池的总体结构:Java类所对应的常量池主要由常量池数量与常量池数组(常量表)这两部分共同构成。常量池数量紧跟在主版本号后面,占据2个字节;常量池数组则紧跟在常量池数量之后。常量池数组与一般的数组不同的是,常量池数组中不同的元素类型、结构都是不同的,长度当然也就不同;但是,每一种元素的第一个数据都是一个u1类型,该字节是个标志位,占据1个字节。JVM在机械常量池时,会根据这个u1类型来获取元素的具体类型。值得注意的是,常量池数组中元素的个数=常量池数 - 1(其中0暂时不适用),目的是满足某些常量池索引值得数据在特定情况下需要表达【不引用任何一个常量池】的含义;根本原因在于,索引为0也是一个常量(保留常量),只不过它部位与常量表中,这个常量就对应null值;所有常量池的索引从1而非0开始。
如图所示,紧跟在主版本后面的2个字节为0x0022,即十进制的34,这就代表常量池中的常量有33项。