最近在看《深入理解java虚拟机》这本书,感觉还不错,写些博客来记录下学习过程(这里对应的是6.3)。
这是书上的原始 java 类,我在上面多加了一个 ina() 方法。
package org.fenixsoft.clazz;
public class TestClass{
private int m;
public int inc(){
return m+1;
}
public int ina(){
return m+1;
}
}
下面看看 class 格式要求(图片是从书上copy来的):
class文件采用无符号数和表的格式来描述数据的存储方式,无符号数分为 u1,u2,u4,u8 四种,分表对应 1、2、4、8 字节,表是由无符号数或者其他的表组成的一种复合数据类型,整个class 文件就可以看成一张 表。在这里我只是简单的介绍了下,想要详细理解的同学,可以参考下其他文档资料。
class 文件对格式的要求是非常严格的,class文件的加载顺序和数量都是严格按照上图进行的。
关于这张表的各个类型我结合下面的几张图进行描述:
E:\>javac TestClass.java
E:\>javap -verbose TestClass.class
下面这张图是 class 文件的 16 进制文件,windows 系统 可以用 winHex 这个软件打开,
好了现在说说第一张图的字段信息吧
<1> 第一个字段(在这里我用字段描述这个名称):magic 字段 占用四个字节 这四个字节分别对应:CAFE BA BE 。这个字段是为了说明该文件能够被java虚拟机接受,没有其他作用。
<2,3> 第二个字段 和 第三个字段 说的是 jdk 所能支持的版本号,在第二张图上 可以清楚地看的到,我采用的是1.7的版本,这两个字段在 class 十六进制文件中分别对应
0000 0033 这两个字节。
分析到这里我们可以看出 class 文件的 加载时严格按照顺序进行加载的。
<4> 第四个字段 是 constant_pool_count 这个字段是描述 常量池中 常量个数,也就是接下来第五个字段的个数。细心的同学可能发现了以下的一条规律:在 表 字段类型的前面都有一个字段来描述该表的数量,在这里用的就是 constant_pool_count 来描述 constant_pool 这个字段的, 接着 class 十六进制文件 数下去,这个 constant_pool_count 对应的字节是0014 用十六进制表示十进制 是 20 。说明有 20 个常量,可是在 第二张图中却只显示了 19 个常量,这是因为第 0 项 常量 留着是由特殊考虑的,这里我们就暂时不考虑他了吧。
<5>第五个字段 constant_pool 这是常量池,在第二张图中可以看出该常量池有 19 个常量,这里需要注意的是每一个常量都对应着一张表,常量池一共有 14 种表类型。
现在开始从第一个常量池开始加载, 需要注意的是每一个常量表 都有一个 tag 字段, 占用 一个字节,该字节对应该常量的入口,本例中的第一个 入口是0A 在第三张图中按顺序可以找到,0A 在十进制中是 10,在上图中 可以看到 10 对应的是 CONSTAN_Methodref_info方法引用,在第二张图中看到第一个常量是:#1 = Methodref , 指向的是 #4,#16 对应 class 文件的0004 0010,第二个常量的入口是 09,对应的是 CONSTAN_Fieldref_info ,对应二图中的 #2 = Fieldref,指向 #3,#17对应的 class 文件的 00030011 。就这样一直加载完常量池的所有常量。这里我就不一一列举了,详细的可以参考书本。这里附加所有的常量表定义: