<强>前言:
强>
身为一个java程序员,怎么能不了解JVM呢,倘若想学习JVM,那就又必须要了解类文件,类之于虚拟机,就如鱼之于水,虚拟机因为类而有了生命。《深入理解java虚拟机》中花了一整个章节来讲解类文件,可是看完后,一直都还是迷迷糊糊,似懂非懂。正好前段时间看见一本书很不错:《自己动手写java虚拟机》,作者利用去语言实现了一个简单的JVM,虽然没有完整实现JVM的所有功能,但是对于一些对JVM稍感兴趣的人来说,可读性还是很高的。作者讲解的很详细,每个过程都分为了一章,其中一部分就是讲解如何解析类文件。
这本书不太厚,很快就读完了,读完后,收获颇丰。但是纸上得来终觉浅,绝知此事要躬行,我便尝试着自己解析类文件.go语言虽然很优秀,但是终究不熟练,尤其是不太习惯其把类型放在变量之后的语法,还是老老实实用java吧。
话不多说,先贴出项目地址:https://github.com/HalfStackDeveloper/ClassReader
<强>类文件
强>
<强>什么是类文件? 强>
java之所以能够实现跨平台,便在于其编译阶段不是将代码直接编译为平台相关的机器语言,而是先编译成二进制形式的java字节码,放在类文件之中,虚拟机再加载类文件,解析出程序运行所需的内容。每个类都会被编译成一个单独的类文件,内部类也会作为一个独立的类,生成自己的类。
<>强基本结构
强>
随便找到一个类文件,用崇高的文本打开是这样的:
是不是一脸懵逼,不过java虚拟机规范中给出了类文件的基本格式,只要按照这个格式去解析就可以了:
类文件{ u4魔法; 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_count); u2 fields_count; field_info字段(fields_count); u2 methods_count; method_info方法(methods_count); u2 attributes_count; attribute_info属性(attributes_count); }
类文件中的字段类型有u1, u2,愉快,这是什么类型呢?其实很简单,就是分别表示1个字节,2个字节和4个字节。
开头四个字节为:魔法,是用来唯一标识文件格式的,一般被称作神奇数字(魔数),这样虚拟机才能识别出所加载的文件是否是类格式,类文件的魔数为cafebabe。不只是类文件,基本上大部分文件都有魔数,用来标识自己的格式。
接下来的部分主要的是类文件的一些信息,如常量池,类访问标志,父类,接口信息,字段,方法等,具体的信息可参考《Java虚拟机规范》。
<>强解析强>
<强>字段类型强>
上面说到类文件中的字段类型有u1, u2,愉快,分别表示1个字节,2个字节和4个字节的无符号整数. java中,int,长分别为2,4,8个字节的有符号整数,去掉符号位,刚好可以用来表示u1, u2, u4。
公开课U1 { 公共静态短阅读(InputStream InputStream) { byte[]字节=新字节[1]; 尝试{ read(字节); }捕捉(IOException e) { e.printStackTrace (); } 短的价值=https://www.yisu.com/zixun/(短)[0]& 0 xff(字节); 返回值; } } 公开课U2 { 公共静态int读(InputStream InputStream) { byte[]字节=新字节[2]; 尝试{ read(字节); }捕捉(IOException e) { e.printStackTrace (); } int num=0; for (int i=0;我之前 <强>常量池
强>定义好字段类型后,我们就可以读取类文件了,首先是读取魔数之类的基本信息,这部分很简单:
FileInputStream inputStream=new FileInputStream(文件); 类文件类文件=new类文件(); 类文件。魔法=U4.read (inputStream); 类文件。minorVersion=U2.read (inputStream); 类文件。majorVersion=U2.read (inputStream);解析Java类文件过程