Class文件解析(手写一个Class文件解析器)

学习JVM的第一课便是Class文件解析,这也是了解JVM执行引擎的基础,网上关于Class文件解析的文章也是数不胜数,这次就玩点不一样的,使用Java语言来写一个Class文件解析器,主要的目的是在于了解Class文件结构,使用什么语言倒是没什么所谓。

在这里我不会介绍class文件中诸如常量元素结构、ConstanValue属性表结构等知识,这些随便一搜一大把,我只会介绍如何实现的有关步骤;

由于在Class文件中字节是以无符号的byte类型存储的,而Java语言中则没有提供无符号的数值类型,所以索性采用short类型保存每一个字节数据,由此,在Java中无法表示无符号的64位long类型和double类型,所以就不进行实现了。总体来说难度是不大的,无非就是按部就班的逐字节解析;

接下来主要说下实现的总体流程:

  1. 通过指定的文件路径获取byte数组,而由于Java中byte是有符号的,所以需要将其转为short;
  2. 解析魔术版本和编译版本,两个固定属性,都是由两个u2类型组成;
  3. 解析常量池,JDK8虚拟机规范定义了14种常量类型,通过tag区分类型,首先解析u2类型的常量池大小,再循环解析,循环内部通过u2类型的tag获取具体的常量类型,所有常量类型的结构都是固定的,需要注意的是常量池第一个元素为空,其次64位的long和double需要占用两个常量位;
  4. 接下来的是类访问标识、当前类全限定名称在常量池的索引、直接父类全限定名称在常量池的索引、实现的接口数量,这些都是u2类型,需要注意的是如果解析的是Object类,那么它的直接父类全限定名称在常量池的索引为0,这估计也是常量池第一个元素为空的原因;
  5. 接下来是实现的接口信息,它们的全限定名称在常量池的索引以u2类型数组的方式保存,上面已经确定了实现的接口数量,所以此处也是固定的;
  6. 接下来是字段信息了,首先是一个u2类型的字段数量,需要注意的是仅仅是显示定义的字段,隐式继承的不算,之后对字段数量进行遍历,由此来构建每一个字段,对于每一个字段而言,都是访问标识、字段名称在常量池的索引、字段类型名称在常量池的索引、属性表数量,这些都是u2类型,最后就是属性表了,字段的属性表都是ConstanValue,且只有被static final修饰的常量才会带有属性表;
  7. 字段过后就是方法了,与字段类似,都是数量开头,再通过对数量的遍历来构建每一个方法,对于每一个方法而言,也都是访问标识、方法名称在常量池的索引、方法类型名称在常量池的索引、属性表数量,需要注意的是方法类型名称不是返回类型名称。例如主方法,它的类型名称为([Ljava/lang/String;)V ,这代表着他接受一个java.lang.String[]类型的参数,且返回值是void,最后也同样是属性表,方法的属性表都是Code类型,且Code类型中还可以包含其他属性,这估计是Class文件解析中最具有挑战性的了;
  8. 最后是属性信息,由u2类型的属性数量和具体的属性表组成,在JVM定义了23中属性(jdk8虚拟机规范),它们各司其职,例如ConstanValue和Code只能分别作用于字段、方法,我实现的Class解析器仅仅实现了5种最基本的属性,其中SourceFile是每个Class文件不可或缺的,它存储了源码文件名称在常量池的索引;

下面准备一个Java测试文件(ps:目前的Class文件解析器没有全面考虑属性表,所义定义测试文件需谨慎,避免出现xx属性暂不支持):

public class Hello
{
	private static final String str="hello world";
	private final static double PI=3.1415926;
	public int a=99;
	public Short s;
	private Object o=new Object();
	
	public static void main(String[] args)
	{
		System.out.println("hello");
	}
	
	private void test(int a,int b)
	{
		this.a=a;
		int c=a+b;
	}
}

将其编译后使用javap -verbose Hello查看字节码信息:

简单对比自定义的class文件解析器:

最后简单总结下,虽然完成了简单的实例效果,但距离标准还是差很多,但对于学习JVM而言意义重大,Class文件看起来是二进制的字节码,从而感到杂乱无章,但理解之后可以体会其精简优雅之道。

资源下载:https://github.com/lsm1998/jvm

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值