当前位置: 首页 > 后端技术 > Java

【JVM知识汇总-7】Class文件结构

时间:2023-04-01 15:37:08 Java

【JVM知识汇总-1】JVM内存模型【JVM知识汇总-2】HotSpot虚拟机对象【JVM知识汇总-3】垃圾收集策略与算法【JVM知识汇总-4]HotSpot垃圾收集器【JVM知识汇总-5】内存分配与回收策略【JVM知识汇总-6】JVM性能调优【JVM知识汇总-7】Class文件结构【JVM知识汇总-8】类【JVM知识汇总】-9]类加载的过程[JVM知识总结-10]类加载器JVM的“独立性”说到JVM的独立性,主要有两个:平台独立性:任何操作系统都可以运行Java代码语言独立性:JVM可以运行Java以外的代码。Java源代码首先需要使用Java编译器编译成.class文件,然后JVM执行.class文件,程序开始运行。JVM只识别.class文件,并不关心生成.class文件的语言是什么,只要.class文件符合JVM规范就可以运行。目前JRuby、Jython、Scala等语言都可以在JVM上运行。它们有自己的语法规则,但是它们的编译器可以将它们的源代码编译成符合JVM规范的.class文件,这样就可以借助JVM运行了。Java语言中各种变量、关键字、操作符号的语义最终都是由多个字节码命令组成的,所以字节码命令所能提供的语义描述能力肯定会比Java语言本身更强大。因此,有一些语言特性是Java语言本身不能有效支持的,但并不代表字节码本身不能有效支持。类文件结构类文件是二进制文件,其内容有严格的规范。文件中没有空格,都是连续的0/1。Class文件中的所有内容分为两种:无符号数和表格。无符号数:无符号数表示Class文件中的值,这些值没有任何类型,只是长度不同。u1、u2、u4、u8分别表示1/2/4/8字节的无符号数。表:由多个无符号数或其他表作为数据项组成的复合数据累加。Class文件具体由以下部分组成:magicnumber版本信息常量池accessflagclassindex,parentclassindex,interfaceindexsetfieldtablesetmethodtablesetattributetablesetmagicnumberclass文件的前4个字节称为magicnumber,用于表示Class文件的类型。以十六进制表示的“CAFEBABE”幻数作为Class文件的幻数,相当于文件后缀,但后缀容易被修改,不安全,所以更适合用来标识文件类型在类文件中。magicnumber后面的4个字节的版本信息是版本信息,5-6个字节表示次版本号,7-8个字节表示主版本号,表示当前Class文件使用的是哪个版本的JDK。高版本的JDK可以向后兼容以前版本的Class文件,但是不能运行以后版本的Class文件。即使文件格式没有改变,虚拟机也必须拒绝执行超过其版本号的Class文件。常量池版本信息之后是常量池,里面存放两类常量:字面量常量字面量常量就是我们在程序中定义的字符串和final修饰的值。符号引用符号引用是我们定义的各种名称:类和接口的完全限定名、字段名和描述符、方法名和描述符。常量池的特点常量池中常量的个数是不固定的,所以在常量池的开头放了一个u2类型的无符号数,用来存放当前常量池的容量。常量池中的每一个常量都是一个表,表示最开始的第一位是一个u1类型的标志(tag),代表当前常量属于哪种常量类型。ConstanttypetagdescriptionintheconstantpoolCONSTANT_utf8_info1UTF-8encodedstringCONSTANT_Integer_info3integerliteralCONSTANT_Float_info4floatingpointliteralCONSTANT_Long_info5longintegerliteralCONSTANT_Double_info6doubleprecisionfloatingpointliteralCONSTANT_Class_info7classorinterfacesymbolreferenceCONSTANT_String_string类型字面量CONSTANT_Fieldref_info9字段的符号引用CONSTANT_Methodref_info10类中方法的符号引用CONSTANT_InterfaceMethodref_info11接口中方法的符号引用CONSTANT_NameAndType_info12字段或方法的符号引用CONSTANT_MethodHandle_info15表示方法句柄CONSTANT_MethodType_info16标识方法类型CONSTANT_InvokeDynamic_info18表示一个动态方法调用点对于CONSTANT_Class_info(此类型的Aconstantrepresentsasymbolicreferencetoaclassoraninterface),anditstwo-dimensionaltablestructureisasfollows:typenamenumberu1tag1u2name_index1tagisaflagbitusedtodistinguishtheconstanttype;name_indexisanindexvalue,whichpointstoaCONSTANT_Utf8_infotypeconstantintheconstantpool,Thisconstantrepresentsthefullyqualifiednameofthisclass(orinterface).Ifthevalueofname_indexis0x0002,itpointstothesecondconstantintheconstantpool.ThestructureoftheCONSTANT_Utf8_infoconstantisasfollows:typenamenumberu1tag1u2length1u1byteslengthtagisthetypeofthecurrentconstant:lengthindicatesthelengthofthestring;bytesisthecontentofthestring(usingabbreviatedUTF8encoding).Theaccessflagisimmediatelyaftertheendoftheconstantpool.Twobytesrepresenttheaccessflag,whichisusedtoidentifysomeclassorinterface-levelaccessinformation,including:whethertheclassisaClassoraninterface:whetheritisdefinedasapublictype;whetheritismodifiedbyabstract/final.类索引、父类索引、接口索引集合类索引和父类索引都是u2类型的数据,接口索引的集合是u2类型数据的集合。class文件是由这三项数据的继承关系决定的。类索引用于确定本类的全限定名,父类的索引用于确定父类的全限定类名。由于Java不允许多重继承,所以只有一个父类索引。除了java.lang.Object,所有的Java类都有父类,所以除了java.lang.Object,所有的Java类都有父类索引。为0。一个类可能实现多个接口,所以用一个接口索引集合来描述。这个集合的第一项是u2类型的数据,表示索引表的容量,后面是接口的名称索引。类索引和父类索引由两个u2类型的索引值表示,每个索引值都指向一个CONSTANT_Class_info类型的类描述符常量,通过该常量的总索引值可以找到全限定名在CONSTANT_Utf8_info字符串类型的常量中定义的字符。字段表集合字段表集合存储了该类涉及的成员变量,包括实例变量和类变量,但不包括方法中的局部变量。每个字段表只代表一个成员变量,该类的所有成员变量组成一个字段表集合。字段表结构如下:类型名个数表示u2access_flags1字段的访问标志,与类u2name_index1字段名u2descriptor_index1描述符的索引略有不同,用于描述数据类型场。基本数据类型用大写字母表示;对象类型由“L对象类型的完全限定名称”表示。u2attributes_count1属性表集合的长度u2attributesattributes_count属性表集合用于存储属性的附加信息,例如属性值。从父类(或接口)继承的字段不会出现在字段表集合中,但可能会出现原始Java代码中不存在的字段。例如,为了在内部类中维护对外部类的访问,它们会自动添加一个指向外部类实例的字段。方法表集合方法表结构类似于属性表。volatile关键字和transition关键字不能修饰方法,所以方法表的访问标志中没有ACC_VOLATILE和ACC_TRANSIENT标志。方法表的属性表集合中有一个Code属性表,用于存放编译器对当前方法编译出的字节码指令。属性表集合每个属性对应一个属性表。属性表结构如下:类型名个数u2attribute_name_index1u4attribute_length1u1infoattribute_length