0

0

实现一个Java Class解析器的实力代码分享

黄舟

黄舟

发布时间:2017-03-18 10:41:32

|

2895人浏览过

|

来源于php中文网

原创

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

Class文件

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

根据Java虚拟机规范,Class文件采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。Java虚拟机规范定义了u1u2u4u8来分别表示1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者是字符串。表是由多个无符号数或者其它表作为数据项构成的符合数据类型,表用于描述有层次关系的符合结构的数据,因此整个Class文件本质上就是一张表。在ClassAnalyzeru1u2u4u8分别对应于byteshortintlongClass文件被描述为如下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虚拟机规范定义了多种常量类型,每一种常量类型都有自己的结构。常量池本身是一个表,在解析时有几点需要注意。

立即学习Java免费学习笔记(深入)”;

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

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

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

    论论App
    论论App

    AI文献搜索、学术讨论平台,涵盖了各类学术期刊、学位、会议论文,助力科研。

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

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

字段表用于描述类或者接口中声明的变量,字段包括类级变量以及实例级变量。字段表的结构包含一个u2类型的access_flags、一个u2类型的name_index、一个u2类型的descriptor_index、一个u2类型的attributes_countattributes_countattribute_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属性中,codeLengthcode分别用于存储字节码长度和字节码指令,每条指令即一个字节(u1类型)。在虚拟机执行时,通过读取code中的一个个字节码,并将字节码翻译成相应的指令。另外,虽然codeLength是一个u4类型的值,但是实际上一个方法不允许超过65535条字节码指令。

代码实现

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

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

53

2026.01.31

高干文在线阅读网站大全
高干文在线阅读网站大全

汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

40

2026.01.31

无需付费的漫画app大全
无需付费的漫画app大全

想找真正免费又无套路的漫画App?本合集精选多款永久免费、资源丰富、无广告干扰的优质漫画应用,涵盖国漫、日漫、韩漫及经典老番,满足各类阅读需求。阅读专题下面的文章了解更多详细内容。

50

2026.01.31

漫画免费在线观看地址大全
漫画免费在线观看地址大全

想找免费又资源丰富的漫画网站?本合集精选2025-2026年热门平台,涵盖国漫、日漫、韩漫等多类型作品,支持高清流畅阅读与离线缓存。阅读专题下面的文章了解更多详细内容。

12

2026.01.31

漫画防走失登陆入口大全
漫画防走失登陆入口大全

2026最新漫画防走失登录入口合集,汇总多个稳定可用网址,助你畅享高清无广告漫画阅读体验。阅读专题下面的文章了解更多详细内容。

13

2026.01.31

php多线程怎么实现
php多线程怎么实现

PHP本身不支持原生多线程,但可通过扩展如pthreads、Swoole或结合多进程、协程等方式实现并发处理。阅读专题下面的文章了解更多详细内容。

1

2026.01.31

php如何运行环境
php如何运行环境

本合集详细介绍PHP运行环境的搭建与配置方法,涵盖Windows、Linux及Mac系统下的安装步骤、常见问题及解决方案。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php环境变量如何设置
php环境变量如何设置

本合集详细讲解PHP环境变量的设置方法,涵盖Windows、Linux及常见服务器环境配置技巧,助你快速掌握环境变量的正确配置。阅读专题下面的文章了解更多详细内容。

0

2026.01.31

php图片如何上传
php图片如何上传

本合集涵盖PHP图片上传的核心方法、安全处理及常见问题解决方案,适合初学者与进阶开发者。阅读专题下面的文章了解更多详细内容。

2

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 8万人学习

Java 教程
Java 教程

共578课时 | 53.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号