java虚拟机之class文件解读
解读前提
我们知道,java的源码文件经过编译器的编译就得到了字节码文件,也就是class文件。我们一直以来,关心的都是源码文件。身为程序员的你,是否跟我一样好奇过class文件里面是什么,是否也打开过class文件,然后发现一堆看不懂的乱码而放弃。那么这篇博客就是介绍如何来解读class文件。
首先我们要知道class文件的内容是以二进制的格式存在的,这也就是为什么我们用一些工具打开这些文件的时候,会出现乱码的根源。因为这些工具尝试将class文件的内容用一些给定的编码进行解析,比如UTF-8、GBK等,这样子解析出来的内容必然是没有意义乱码。
那么我们该如何来查看class文件的内容?
总的思想就是,将二进制的内容转换成十六进制进行查看。原因是,class文件的内容都是字节流组成的,一个字节有八位。16位、32位、64位的数据将使用2个、4个、8个字节来表示。一个字节的内容转换成十六进制,就是两位,方便观看。关于这一步,有比较多的方法,我这里使用的是使用Editplus的Hex Viewer来查看。
- 使用Editplus打开class文件,提示是否选择另外一种编码,点击是
- 在编码选择窗口中,选择Hex Viewer,并点击OK
- 现在我们看到的内容就是16进制的。最左边的内容表示一行开始的偏移量。例如:CA的偏移量为00000000,那么FE的偏移量为00000001,直到第一行的最末尾,07的偏移量为0000000F。第二行开始00的偏移量为00000010,由此可见,这个偏移量也是十六进制的。其实这个偏移量也就是字节的索引位置。记住,两个十六进制为一个字节。
解读第一步,弄清楚class文件的整体结构
class文件的内容可不是随意组织的,Java虚拟机规范里面对class文件的结构进行的规定。每个class文件对应如下所示的ClassFile结构。
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
看不懂什么意思没关系,这是很正常的,接着看下去,我会对ClassFile进行解释。这里有一点要先跟大家说明。就是ClassFile结构中的u2、u4
分别代表的是2个字节、4个字节
,如果后面的内容中出现了类似的结构,也是以此类推,比如u1
表示1个字节
,u8
表示8个字节
。
解读第二步 ClassFile文件解释
魔数
百度百科上对魔数的解释是:
根据ClassFile结构,我们可以知道,class文件的开始是一个由四个字节长组成的魔数
u4 magic;
表现在class文件中,则如下所示:
由此我们可以知道,class文件以魔数CA FE BA BE
开始,Java虚拟机辨别它为class文件。如果不相信,可以打开多个class文件进行确认,每个class文件的前四个字节都是CA FE BA BE
,不会改变。
副版本号
紧接在魔数之后的,是用两个字节表示的副版本号。在魔数跟副版本号之间,没有任何间隔。
u2 minor_version;
在class文件中表示为:
由此可知,这个class文件的副版本号为0。
主版本号
紧接在副版本号之后的是主版本号,主版本号同样也是用两个字节表示。
u2 major_version;
在class文件中表示为:
由此可知,主版本号为0034
,因为这是16进制的,转换成十进制就是52
。JDK的版本跟class版本对应关系如下,由此可知,这个class文件由1.8版本的JDK编译得来。
JDK版本 | classs版本 |
---|---|
JDK 1.8 | 52 |
JDK 1.7 | 51 |
JDK 1.6 | 50 |
JDK 1.5 | 49 |
JDK 1.4 | 48 |
JDK 1.3 | 47 |
JDK 1.2 | 46 |
JDK 1.1 | 45 |
参考书籍
Java虚拟机规范(JavaSE7)