最近在写一个私人项目,名字叫做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中u1、u2、u4和u8分别对应于byte、short、int和long,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的源码已放在了
https://github.com/tinylcy/ClassAnalyzer上。在ClassAnalyzer的README中,我以一个类的Class文件为例,对该Class文件的每个字节进行了分析,希望对大家的理解有所帮助。
分享到:
相关推荐
通过实现这个Java Class解析器,我们可以更深入地理解Java Class文件的内部结构和Java虚拟机的工作原理。这不仅有助于优化代码,也能为调试、分析和逆向工程提供强大的工具。虽然JDK的javap工具已经提供了基本的反...
本文将探讨如何实现一个Java Class解析器,以解析这些字节码文件。 首先,我们要知道Class文件的结构。每个Class文件都是以固定的魔数(magic number)开始,用于识别文件格式,紧接着是两个u2类型的数值,分别代表...
Java Class文件解析是Java开发中的一个重要概念,它涉及到Java虚拟机(JVM)如何理解和执行程序的核心机制。这篇博文的链接虽然无法直接访问,但从标题和标签我们可以推测,内容可能涵盖了对Java字节码的深入理解和...
Java解析Class文件是Java开发中的一个重要环节,它涉及到对字节码的理解和处理。Class文件是Java编译器将源代码编译后的结果,包含了类的结构信息、方法定义、常量池等关键数据。理解并能解析Class文件,对于进行JVM...
class文件解析器class文件解析器class文件解析器
Java的SQL解析器JSQLPaser是一个强大的开源库,专门设计用于处理SQL语句的解析工作。这个库允许开发者分析SQL语句的结构,提取出其中的关键元素,如列名、表名、别名以及查询条件,从而在Java应用程序中实现对SQL的...
一个.class文件包含了Java程序的基本结构单元,如类、接口、字段和方法定义。它采用特定的字节码格式,使得虚拟机(JVM)能够理解并执行其中的指令。这些字节码由一系列的常量池、访问标志、字段、方法和属性组成。...
学习和理解这个实现可以帮助你掌握编译原理的基础知识,包括词法分析、语法分析和抽象语法树的构建,这些都是构建任何编程语言解析器的核心概念。此外,对于Java程序员来说,了解如何在实际项目中应用这些理论知识,...
首先,APK实际上是一个ZIP格式的压缩包,包含了AndroidManifest.xml、资源文件、dex字节码等。传统的解析方法是通过读取ZIP文件并解析XML文件,但这对于经过加密或加壳处理的APK可能无效,因为它们可能对原始数据...
"JAVA CLASS文件查看器"就是这样一个工具,它的主要功能是解析并显示这些二进制类文件的内容。 这个工具的特点是小巧和绿色,意味着它不会占用大量硬盘空间,且无需安装即可使用,用户只需下载解压后即可开始操作。...
本文旨在深入探讨JavaClass文件的结构特点,并基于此实现一个JavaClass文件的校验器。 #### JavaClass文件校验的目的和原理 JavaClass文件的校验过程是为了确保加载到Java虚拟机(JVM)上的Class文件具有正确的...
这些类可能包括一个解析器类,它使用某种解析策略(如递归下降解析、LL解析或LR解析),以及一个求值器类,它负责执行解析后的AST。源码可能还包括辅助类,如符号表管理器,用于存储变量和函数定义。 `build`目录...
总之,Java Class翻译器汉化版是一个强大的辅助工具,它可以帮助开发者深入理解已编译的Java程序,进行调试和定制,同时,也能提升开发者对Java底层机制的认知。无论是为了工作还是学习,掌握这样的工具都将极大提升...
1. 创建一个实现DefaultHandler或ContentHandler接口的类,重写其中的方法,如startElement()、endElement()和characters(),用于处理XML文档的结构和数据。 2. 实例化SAX解析器,通常通过SAXParserFactory类的new...
总的来说,JavaClass反编辑器是一款强大的工具,它提供了一种深入探究Java类文件内部机制的方式,对于开发者来说,无论是为了学习、调试还是其他目的,都是一个不可或缺的辅助工具。通过熟练掌握此类工具的使用,...
以下是一个简单的示例,展示了如何使用`JavaCompiler` API编译源文件: ```java import javax.tools.*; import java.io.File; import java.util.ArrayList; import java.util.List; public class DynamicCompiler ...
### 使用Java XML解析器实现一个简单的XML文档操作 #### 一、引言 XML(Extensible Markup Language,可扩展标记语言)是一种用于标记数据的语言,它允许开发者自定义标签,以此来描述数据的结构和意义。Java 提供...
JavaClass反编辑器是一款专门用于查看和分析Java字节码的工具,它的主要功能是对`.class`文件进行反编译,将编译后的二进制代码还原为接近源代码的可读格式。这对于开发者来说非常有用,特别是在进行逆向工程、代码...
**jsoup Java HTML解析器详解** jsoup是一个用于处理实际世界HTML的Java库。它提供了非常方便的方法来提取和操作数据,使用DOM,CSS以及类似于jQuery的API。jsoup能够理解HTML的不完美之处,同时提供了强大的功能来...
在Java中实现解释器模式,我们可以创建一个抽象表达式接口,然后为每种特定的语法结构创建一个具体表达式类。这个模式在处理简单的语言或表达式时特别有用,例如配置文件、简单的计算器或者SQL查询的简化版本。 ...