全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Java Class 解析器实现方法示例

最近在写一个私人项目,名字叫做ClassAnalyzer,ClassAnalyzer的目的是能让我们对Java Class文件的设计与结构能够有一个深入的理解。主体框架与基本功能已经完成,还有一些细节功能日后再增加。实际上JDK已经提供了命令行工具javap来反编译Class文件,但本篇文章将阐明我实现解析器的思路。

Class文件

作为类或者接口信息的载体,每个Class文件都完整的定义了一个类。为了使Java程序可以“编写一次,处处运行”,Java虚拟机规范对Class文件进行了严格的规定。构成Class文件的基本数据单位是字节,这些字节之间不存在任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,单个字节无法表示的数据由多个连续的字节来表示。

根据Java虚拟机规范,Class文件采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。Java虚拟机规范定义了u1、u2、u4和u8来分别表示1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者是字符串。表是由多个无符号数或者其它表作为数据项构成的复合数据类型,表用于描述有层次关系的复合结构的数据,因此整个Class文件本质上就是一张表。在ClassAnalyzer中,byte、short、int和long分别对应u1、u2、u4和u8数据类型,Class文件被描述为如下Java类。

public class ClassFile {
 public U4 magic;       // magic
 public U2 minorVersion;      // minor_version
 public U2 majorVersion;      // major_version
 public U2 constantPoolCount;    // constant_pool_count
 public ConstantPoolInfo[] cpInfo;   // cp_info
 public U2 accessFlags;      // access_flags
 public U2 thisClass;      // this_class
 public U2 superClass;      // super_class
 public U2 interfacesCount;     // interfaces_count
 public U2[] interfaces;      // interfaces
 public U2 fieldsCount;      // fields_count
 public FieldInfo[] fields;     // fields
 public U2 methodsCount;      // methods_count
 public MethodInfo[] methods;    // methods
 public U2 attributesCount;     // attributes_count
 public BasicAttributeInfo[] attributes;  // attributes
}

如何解析

组成Class文件的各个数据项中,例如魔数、Class文件的版本等数据项、访问标志、类索引、父类索引,它们在每个Class文件中都占用固定数量的字节,在解析时只需要读取相应数量的字节。除此之外,需要灵活处理的主要包括4部分:常量池、字段表集合、方法表集合和属性表集合。字段和方法都可以具备自己的属性,Class本身也有相应的属性,因此,在解析字段表集合和方法表集合的同时也包含了属性表的解析。

常量池占据了Class文件很大一部分的数据,用于存储所有的常量信息,包括数字和字符串常量、类名、接口名、字段名和方法名等。Java虚拟机规范定义了多种常量类型,每一种常量类型都有自己的结构。常量池本身是一个表,在解析时有几点需要注意。

每个常量类型都通过一个u1类型的tag来标识。

表头给出的常量池大小(constantPoolCount)比实际大1,例如,如果constantPoolCount等于47,那么常量池中有46项常量。

常量池的索引范围从1开始,例如,如果constantPoolCount等于47,那么常量池的索引范围为1~46。设计者将第0项空出来的目的是用于表达“不引用任何一个常量池项目”。

CONSTANT_Utf8_info型常量的结构中包含u1类型的tag、u2类型的length和由length个u1类型组成的bytes,这length字节的连续数据是一个使用MUTF-8(Modified UTF-8)编码的字符串。MUTF-8与UTF-8并不兼容,主要区别有两点:一是null字符会被编码成2字节(0xC0和0x80);二是补充字符是按照UTF-16拆分为代理对分别编码的,相关细节可以看这里(变种UTF-8)。

属性表用于描述某些场景专有的信息,Class文件、字段表和方法表都有相应的属性表集合。Java虚拟机规范定义了多种属性,ClassAnalyzer目前实现了对常用属性的解析。和常量类型的数据项不同,属性并没有一个tag来标识属性的类型,但是每个属性都包含有一个u2类型的attribute_name_index,attribute_name_index指向常量池中的一个CONSTANT_Utf8_info类型的常量,该常量包含着属性的名称。在解析属性时,ClassAnalyzer正是通过attribute_name_index指向的常量对应的属性名称来得知属性的类型。

字段表用于描述类或者接口中声明的变量,字段包括类级变量以及实例级变量。字段表的结构包含一个u2类型的access_flags、一个u2类型的name_index、一个u2类型的descriptor_index、一个u2类型的attributes_count和attributes_count个attribute_info类型的attributes。我们已经介绍了属性表的解析,attributes的解析方式与属性表的解析方式一致。

Class的文件方法表采用了和字段表相同的存储格式,只是access_flags对应的含义有所不同。方法表包含着一个重要的属性:Code属性。Code属性存储了Java代码编译成的字节码指令,在ClassAnalyzer中,Code对应的Java类如下所示(仅列出了类属性)

public class Code extends BasicAttributeInfo {
 private short maxStack;
 private short maxLocals;
 private long codeLength;
 private byte[] code;
 private short exceptionTableLength;
 private ExceptionInfo[] exceptionTable;
 private short attributesCount;
 private BasicAttributeInfo[] attributes;
 ...
 private class ExceptionInfo {
  public short startPc;
  public short endPc;
  public short handlerPc;
  public short catchType;
   ...
 }
}

在Code属性中,codeLength和code分别用于存储字节码长度和字节码指令,每条指令即一个字节(u1类型)。在虚拟机执行时,通过读取code中的一个个字节码,并将字节码翻译成相应的指令。另外,虽然codeLength是一个u4类型的值,但是实际上一个方法不允许超过65535条字节码指令。

代码实现

ClassAnalyzer的源码已放在了GitHub上。在ClassAnalyzer的README中,我以一个类的Class文件为例,对该Class文件的每个字节进行了分析,希望对大家的理解有所帮助。

参考

深入理解Java虚拟机

结束语:以上就是本文关于如何实现一个Java class 解析器的全部内容,希望对大家有所帮助。


# java  # 类方法解析器  # java动态添加外部jar包到classpath的实例详解  # Java 使用getClass().getResourceAsStream()方法获取资源  # java.lang.NoClassDefFoundError错误解决办法  # Java class文件格式之访问标志信息_动力节点Java学院整理  # Java class文件格式之属性详解_动力节点java学院整理  # Java中Class类的作用与深入理解  # 是一个  # 自己的  # 都有  # 多个  # 有一个  # 含着  # 进行了  # 池中  # 也有  # 放在  # 出了  # 目的是  # 一是  # 是由  # 两种  # 有所不同  # 能让  # 采用了  # 并将  # 不存在 


相关文章: 兔展官网 在线制作,怎样制作微信请帖?  官网建站费用明细查询_企业建站套餐价格及收费标准指南  香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南  如何优化Golang Web性能_Golang HTTP服务器性能提升方法  网站制作服务平台,有什么网站可以发布本地服务信息?  大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?  php json中文编码为null的解决办法  购物网站制作公司有哪些,哪个购物网站比较好?  ,想在网上投简历,哪几个网站比较好?  我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?  成都响应式网站开发,dw怎么把手机适应页面变成网页?  建站之星下载版如何获取与安装?  c# 在高并发场景下,委托和接口调用的性能对比  网站制作公司,橙子建站是合法的吗?  网站制作公司排行榜,抖音怎样做个人官方网站  建站之星图片链接生成指南:自助建站与智能设计教程  如何选择高效便捷的WAP商城建站系统?  音响网站制作视频教程,隆霸音响官方网站?  北京营销型网站制作公司,可以用python做一个营销推广网站吗?  c++怎么编写动态链接库dll_c++ __declspec(dllexport)导出与调用【方法】  网站建设制作、微信公众号,公明人民医院怎么在网上预约?  如何注册花生壳免费域名并搭建个人网站?  公司门户网站制作公司有哪些,怎样使用wordpress制作一个企业网站?  建站之星3.0如何解决常见操作问题?  企业微网站怎么做,公司网站和公众号有什么区别?  购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?  nginx修改上传文件大小限制的方法  高防服务器租用如何选择配置与防御等级?  建站之星安装失败:服务器环境不兼容?  如何快速查询域名建站关键信息?  宝塔建站后网页无法访问如何解决?  如何在阿里云服务器自主搭建网站?  如何通过免费商城建站系统源码自定义网站主题与功能?  建站一年半SEO优化实战指南:核心词挖掘与长尾流量提升策略  简历在线制作网站免费,免费下载个人简历的网站是哪些?  网页设计网站制作软件,microsoft office哪个可以创建网页?  如何高效生成建站之星成品网站源码?  盐城做公司网站,江苏电子版退休证办理流程?  广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?  Python路径拼接规范_跨平台处理说明【指导】  太平洋网站制作公司,网络用语太平洋是什么意思?  如何零基础开发自助建站系统?完整教程解析  如何访问已购建站主机并解决登录问题?  ,网站推广常用方法?  如何选择高效响应式自助建站源码系统?  宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?  东莞市网站制作公司有哪些,东莞找工作用什么网站好?  网站专业制作公司,网站编辑是做什么的?好做吗?工作前景如何?  如何通过VPS搭建网站快速盈利?  如何快速搭建高效可靠的建站解决方案? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。