JVM学习笔记(一)--类文件结构

本篇文章将通过一段java代码和它的class文件来了解类文件结构。

什么是class文件?  

class文件是一组以8位字节为基础的二进制数据流

示例代码 Main.java:

 

 1 package javaapplication1;
 2 
 3 /**
 4  *
 5  * @author yirain
 6  */
 7 public class TestClass {
 8     private int m;
 9     
10     public int inc(){
11         return m + 1;
12     }
13  
14 }

 

 

用16进制编辑器打开Main.class文件如下(图1):

 

看上图的左上角有一个offset,相当于坐标原点,为了避免重复贴图占用太多篇幅,以下数据项的定位都按offset来表述。例如第一个数据项CA,坐标位(000000)。

魔数和Class文件的版本

offset(000000000003) 为魔数CAFEBABE(咖啡宝贝),作用为确定这个文件是否为一个能被虚拟机接受的class文件。

offset(000004到000007),表示版本号位49.0,表示该文件可以被JDK1.6及以上版本的虚拟机执行。

 常量池

接下来是常量池入口。

 

     表1        常量池的项目类型

 

常量表类型 标志值(占1 byte) 描述
CONSTANT_Utf8 1 UTF-8编码的Unicode字符串
CONSTANT_Integer 3 int类型的字面值
CONSTANT_Float 4 float类型的字面值
CONSTANT_Long 5 long类型的字面值
CONSTANT_Double 6 double类型的字面值
CONSTANT_Class 7 对一个类或接口的符号引用
CONSTANT_String 8 String类型字面值的引用
CONSTANT_Fieldref 9 对一个字段的符号引用
CONSTANT_Methodref 10 对一个类中方法的符号引用
CONSTANT_InterfaceMethodref 11 对一个接口中方法的符号引用
CONSTANT_NameAndType 12 对一个字段或方法的部分符号引用

 

 

offset000008到000009) 0x0016(1*16+6-1)为常量池容量计数值,这里是21,也就是说该常量池有21个数据项。

第一个常量:接下来offset(00000A)0x0A,查询常量池项目类型表可知为类中方法的符号引用。

offset(00000B到00000C)0x0004为一个索引值(给出包含所属类名的CONSTANT_Utf8表的索引),表示指向常量池的第四个常量。

offset(00000D到00000E0x0012为一个索引值包含字段名或方法名以及描述符的 CONSTANT_NameAndType表 的索引),表示指向常量池的第18个常量

 

第二个常量:offset(00000F)0x09, 查询常量池项目类型表可知为对一个字段的符号引用。

offset(000010到000011)0x0003为一个索引值,表示指向常量池的第3个常量。

offset(000012到000013)0x0013为一个索引值,表示指向常量池的第19个常量。

 

 

第三个常量:offset(000014)0x07, 查询常量池项目类型表可知为对一个类或接口的符号引用。
offset(000015到000016)0x0014为一个索引值,表示指向常量池的第20个常量。

第四个常量:offset(000017)0x07, 查询常量池项目类型表可知为对一个类或接口的符号引用。
offset(000018到000019)0x0014为一个索引值,表示指向常量池的第21个常量。

第五个常量:offset(00001A)0x01, 查询常量池项目类型表可知为UTF-8编码的Unicode字符串。
offset(00001B到00001C)0x0001为该常量的长度为一个字节,后面紧跟着的)0x6D为该字符串,换算结果是m。

后面的数据项用javap来分析:

 

 

 

由常量表也可验证上面分析是正确的。

 

访问标志

在常量池结束后,后面两个字节为访问标志,用于识别一些类和接口的访问信息,在该例子中,ACC_PUBLIC为真,ACC_SUPER为真,所以offset(000221到000222)为0x0021.

类索引、父类索引和接口索引集合

类索引和父类索引都是u2类型的数据。也就说从偏移地址 000223开始的0x0003, 0x0004,0x0000,查询常量池找出对应的类和父类的常量。

字段表集合

字段表用于描述接口或类中声明的变量。也就说从偏移地址 000229开始0x0001, 表明该字段表只有一个字段表数据。接下来是access_flags为0x0002 , 表明为private。 name_index为0x0005, 表明指向第五个常量m。 接下来为descriptor_index是0x0006,查找常量表可知为I。则语义为

private int m

方法表集合

从偏移地址000251,表明该方法表有两个方法表数据。接下来是access_flags为0x0001 ,表明为public。 name_index为0x0007, 表明指向第7个常量<init>。接下来为descriptor_index是0x0008,查找常量表可知为()v属性表计数器attitudes_count为0x0001, 表明有一项属性,索引值为0x0009:code。

 

posted @ 2018-04-02 22:23  忆雨1992  阅读(235)  评论(0编辑  收藏  举报