解析Java类文件过程

  

<强>前言:
  

  

身为一个java程序员,怎么能不了解JVM呢,倘若想学习JVM,那就又必须要了解类文件,类之于虚拟机,就如鱼之于水,虚拟机因为类而有了生命。《深入理解java虚拟机》中花了一整个章节来讲解类文件,可是看完后,一直都还是迷迷糊糊,似懂非懂。正好前段时间看见一本书很不错:《自己动手写java虚拟机》,作者利用去语言实现了一个简单的JVM,虽然没有完整实现JVM的所有功能,但是对于一些对JVM稍感兴趣的人来说,可读性还是很高的。作者讲解的很详细,每个过程都分为了一章,其中一部分就是讲解如何解析类文件。

  

这本书不太厚,很快就读完了,读完后,收获颇丰。但是纸上得来终觉浅,绝知此事要躬行,我便尝试着自己解析类文件.go语言虽然很优秀,但是终究不熟练,尤其是不太习惯其把类型放在变量之后的语法,还是老老实实用java吧。

  

话不多说,先贴出项目地址:https://github.com/HalfStackDeveloper/ClassReader

  

<强>类文件
  

  

<强>什么是类文件?
  

  

java之所以能够实现跨平台,便在于其编译阶段不是将代码直接编译为平台相关的机器语言,而是先编译成二进制形式的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类文件过程