最近在写一个私人项目,名字叫做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类。
java; gutter: true">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虚拟机类型界说了多种常量范例,每一种常量范例都有本身的布局。常量池自己是一个表,在理会时有几点需要留意。
属性表用于描写某些场景专有的信息,Class文件、字段表和要领表都有相应的属性表荟萃。Java虚拟机类型界说了多种属性,ClassAnalyzer今朝实现了对常用属性的理会。与常量范例的数据项差异,属性并没有一个tag来标识属性的范例,可是每个属性都包括有一个u2范例的attribute_name_index,attribute_name_index指向常量池中的一个CONSTANT_Utf8_info范例的常量,该常量包括着属性的名称。在理会属性时,ClassAnalyzer正是通过attribute_name_index指向的常量对应的属性名称来得知属性的范例。