Java class文件结构(实例篇)
这一篇我们以一个实际的例子,来逐行分析class的二进制格式,从而深入了解class文件结构。
分析代码如下:
package com.sunny.jdk.classfile;/**
* <Description> <br>
*
* @author Sunny<br>
* @version 1.0<br>
* @taskId: <br>
* @createDate 2018/09/17 15:52 <br>
* @see com.sunny.jdk.classfile <br>
*/public class TestClass {
private int m;
public int inc() {
return m + 1;
}}class文件使用winhex打开的二进制结构如下:

下面我们就根据前篇所说的Class的文件结构来解析以下上图中字节流:
1. 魔数
从Class的文件结构我们知道,刚开始的4个字节是魔数,上图中从地址000000000-000000003的内容就是魔数,从上图可知Class的文件的魔数是0xCAFEBABE。
2. 主副版本号
接下来的4个字节是主副版本号,有上图可知从000000004-000000005对应的是0x0000,因此Class的minor_version 为0x0000,从000000006-000000007对应的内容为0x0034,因此Class文件的major_version版本为 0x0034,这正好就是jdk1.8编译后的Class对应的主次版本。
3. 常量池数量
接下来的2个字节从000000008-000000009表示常量池的数量,由上图可以知道其值为0x0016,十进制为22个,但是对于常量池的数量 需要明确一点,常量池的数量是constant_pool_count-1,为什么减一,是因为索引0表示class中的数据项不引用任何常量池中的常 量。所以常量池的个数应该是21个;
4. 常量池
前篇已经说过了常量池中有不同类型的常量,下面就来看看TestClass.class的第一个常量,每个常量都有一个u1类型的tag标识来表示 常量的类型,上图中00000000A处的内容为0x0A,转换成二级制是10,有上面的关于常量类型的描述可知tag为10的常量是Constant_Methodref_info,而Constant_Methodref_info的结构如下:
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
} 其中tag对应上图位置00000000A处的内容为0x0A;class_index是接下来两个字节的数据,对应的上图位置的00000000B-00000000C,其值为0x0004,也就是说指向第四个常量;name_and_type_index指向常量池中类型为CONSTANT_NameAndType_info常量。从上图可以看出name_and_type_index的值为0x0012,对应上图的位置是00000000D-00000000E表示指向常量池中的第18个常量。接下来我们可以找到常量池中所有的常量:
第2个常量:tag对应00000000F位置的内容是0x09,表示CONSTANT_Fieldref_info,其结构如下:
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
} 其中tag对应上图位置00000000F处的内容为0x09;class_index是接下来两个字节的数据,对应的上图位置的000000100-000000101,其值为0x0003,也就是说指向第3个常量;name_and_type_index指向常量池中类型为CONSTANT_NameAndType_info常量。从上图可以看出name_and_type_index的值为0x0013,对应上图的位置是000000102-000000103表示指向常量池中的第19个常量。
第3个常量:tag对应000000104位置的内容是0x07,表示CONSTANT_Class_info,其结构如下:
CONSTANT_Class_info {
u1 tag;
u2 name_index;
} 其中tag对应上图位置000000104处的内容为0x07;name_index是接下来两个字节的数据,对应的上图位置的000000105-000000106,其值为0x0014,也就是说指向第20个常量;
第4个常量:
tag对应000000107位置的内容是0x07,表示CONSTANT_Class_info,其结构如下:
CONSTANT_Class_info {
u1 tag;
u2 name_index;
} 其中tag对应上图位置000000107处的内容为0x07;name_index是接下来两个字节的数据,对应的上图位置的000000108-000000109,其值为0x0015,也就是说指向第21个常量;
第5个常量:
tag对应00000010A位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置00000010A处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的00000010B-00000010C,其值为0x0001,也就是length为1;紧接着后面length个字节表示的数据即为该数据,因为length=1,所以00000010D处的数据0x6D表示的即为该数据,转换成ASCII即为m;
第6个常量:
tag对应00000010E位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置00000010E处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的00000010F-000000200,其值为0x0001,也就是length为1;紧接着后面length个字节表示的数据即为该数据,因为length=1,所以000000201处的数据0x49表示的即为该数据,转换成ASCII即为I;
第7个常量:tag对应000000202位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置000000202处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的000000203-000000204,其值为0x0006,也就是length为6;紧接着后面length个字节表示的数据即为该数据,因为length=6,所以000000205-00000020A处的数据0x3C, 0x69,0x6E,0x69, 0x74, 0x3E表示的即为该数据,转换成ASCII即为<init>;
第8个常量:
tag对应00000020B位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置00000020B处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的00000020C-00000020D,其值为0x0003,也就是length为3;紧接着后面length个字节表示的数据即为该数据,因为length=3,所以00000020E-000000300处的数据0x28, 0x29,0x56表示的即为该数据,转换成ASCII即为()V;
第9个常量:
tag对应000000301位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置000000301处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的000000302-000000303,其值为0x0004,也就是length为4;紧接着后面length个字节表示的数据即为该数据,因为length=4,所以000000304-000000307处的数据0x43, 0x6F,0x64,0x65表示的即为该数据,转换成ASCII即为Code;
第10个常量:
tag对应000000308位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置000000308处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的000000309-00000030A,其值为0x000F,也就是length为15;紧接着后面length个字节表示的数据即为该数据,因为length=15,所以00000030B-000000409处的数据0x4C, 0x69,0x6E,0x65,0x4E,0x75,0x6D,0x62,0x65,0x72,0x54,0x61,0x62,0x6C,0x65表示的即为该数据,转换成ASCII即为LineNumberTable;
第11个常量:
tag对应00000040A位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置00000040A处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的000000409-00000040A,其值为0x0012,也就是length为18;紧接着后面length个字节表示的数据即为该数据,因为length=18,所以00000040B-00000050E处的数据0x4C,0x6F,0x63,0x61,0x6C,0x56,0x61,0x72,0x69,0x61,0x62,0x6C,0x65,0x54,0x61,0x62,0x6C,0x65表示的即为该数据,转换成ASCII即为LocalVariableTable;
第12个常量:
tag对应00000050F位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置00000050F处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的000000600-000000601,其值为0x0004,也就是length为4;紧接着后面length个字节表示的数据即为该数据,因为length=4,所以000000602-000000605处的数据0x74,0x68,0x69,0x73表示的即为该数据,转换成ASCII即为this;
第13个常量:
tag对应000000606位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置000000606处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的000000607-000000608,其值为0x0023,也就是length为35;紧接着后面length个字节表示的数据即为该数据,因为length=35,所以000000609-00000080B处的数据如图:

,转换成ASCII即为Lcom/sunny/jdk/classfile/TestClass;;
第14个常量:
tag对应00000080C位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置00000080C处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的00000080D-00000080E,其值为0x0003,也就是length为3;紧接着后面length个字节表示的数据即为该数据,因为length=3,所以00000080F-000000901处的数据0x69,0x6E,0x63表示的即为该数据,转换成ASCII即为inc;
第15个常量:
tag对应000000902位置的内容是0x01,表示CONSTANT_Utf8_info,其结构如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
} 其中tag对应上图位置000000902处的内容为0x01;length是接下来两个字节的数据,对应的上图位置的000000903-000000904,其值为0x0003,也就是length为3;紧接着后面length个字节表示的数据即为
原创不易,完成人机校验,阅读全文