写在前面的话
class文件结构可以说是一套规范,不一定是Java编译器编译出来的版本,它用来描述一个文件中对应的字段,类,常量池,继承关系等等。值得一提的是这个文件是完全紧凑型的。从第一个字节到最后一个字节,表达的意思按照约定好的严格规范。由于这种字节码可以运行在jvm上实现跨平台的亮点。所以不只是Java语言编译器可以编译成这种文件。class文件是学习jvm中比较重要的一环。我尽量用案例来分析一个class文件的解析。还是少一些理论性的东西.
案例源码
package structureclass.demo;
public class TestClass{
private int m;
public int inc(){
return m+
1;
}
}
class字节码(winhex截图)
字节码部分构成
字节数与类型名称数量
4个magic(魔数)12个minor_version(次版本号)12个major_version(主版本号)12个constant_pool_count(常量池数量,从1开始)1cp_infoconstant_pool(常量池)constant_pool_count - 12个constant_pool_count(常量池数量,从1开始)12个access_flags(访问标志)12个this_class(类索引)12个super_class(父类索引)12个interfaces_count(接口计数器)12个interfaces(接口描述)interfaces_count2个fields_count(字段表集合count)1field_infofields(字段表集合)fields_count2个methods_count(方法表集合count)1method_infomethods(方法表集合)methods_count2个attributes_count(属性表集合count)1attribute_infoattributes(属性表集合)attributes_count
class字节码文件是严格按照这个顺序占位排列的 其中_info后缀叫做为表,我们把它理解成一个数据结构即可.
magic魔数
对应位置:0+4 如图所示,标识这个文件是一个class文件,这个是严格约束的。必须是这个文件才会被识别。可以理解为后缀与魔数的唯一绑定关系。对应结果CAFE BABE
minor_version&&major_version(次版本号和主版本号)
对应位置:0+4+4 虚拟机会向下兼容其版本号,对于高于其对应版本号的文件,直接拒绝,无论格式是否正确。对应结果:JDK1.7.0。此阶段不做过多研究,安装好jdk,随意编译一下即可知道对应的版本号
constant_pool_count(常量池数量)
对应位置:0+4+4+2 constant_pool_count从1开始,所以表示的数要计算结果以后-1, 0表示不引用任何常量 16进制33等于 3*16^0+1*16^1 = 19 -1 = 18
javap -verbose 输出:
λ javap -verbose TestClass.class
Classfile /E:/jvmana/TestClass.class
Last modified 2018-5-18; size 295 bytes
MD5 checksum 4ee039bbc694ca6a1383cb5bebb97d19
Compiled from "TestClass.java"
public class structureclass.demo.TestClass
SourceFile: "TestClass.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#15 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#16 // structureclass/demo/TestClass.m:I
#3 = Class #17 // structureclass/demo/TestClass
#4 = Class #18 // java/lang/Object
#5 = Utf8 m
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 inc
#12 = Utf8 ()I
#13 = Utf8 SourceFile
#14 = Utf8 TestClass.java
#15 = NameAndType #7:#8 // "<init>":()V
#16 = NameAndType #5:#6 // m:I
#17 = Utf8 structureclass/demo/TestClass
#18 = Utf8 java/lang/Object
{
public structureclass.demo.TestClass();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public int inc();
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field m:I
4: iconst_1
5: iadd
6: ireturn
LineNumberTable:
line 8: 0
}
我们可以看到正好是18项常量。与我们的计算结果一致。
那么,我们继续往下看
constant_pool(静态常量池)
未完待续