class文件结构

java语言具有平台无关性,因为有jvm的支持,编译过后的java代码可以在任意平台上运行。java语言经编译后变成class文件,class文件在jvm上运行。现在jvm添加对其他语言的支持,其他语言编译成class文件也可以在jvm上运行,所以,jvm不仅提供了平台无关性,还提供了语言无关性。在jvm规范中定义了class文件格式,所有能够在jvm上运行的class文件必须要满足jvm定义的class文件规范,不是随随便便改个后缀名就能在jvm上运行,那jvm就危险了。

1.class文件结构

class文件是以8位字节流为基础的二进制流,文件中没有任何空格,是按照严格的顺序、长度排定的,每个位置都有特定含义,不允许修改。

class文件的内容是由俩种类型组成:

  • 无符号数:u1,u2,u4,u8分别代表几个字节的无符号数,无符号数主要用来表示数字,索引,数值,字符值等
  • 表:是复合类型,由多个无符号数或表组成

    这里写图片描述

    class文件是按照上表的顺序进行排定的,在其中某些类型的数据不一定时,通过一个前置计数器来确定数量。

2.魔数magic

标识符,相当于文件后缀名,只不过文件后缀名可以修改,是用来确认class文件能否被jvm接受。这可以避免随随便便修改文件后缀名就可以让jvm接受。

3.minor_version、major_version版本号

class文件版本号,高版本的jvm可以运行低版本的class文件,低版本jvm不能运行高版本的class文件。

4.常量池

常量池中的常量数量是不确定的,所以在常量池之前需要有一个常量计数器,用于记录常量池中的常量个数,这样在内存分配时,能够分配指定的空间给常量池。

常量池中主要存放的是字面量和符号引用。
字面量主要为文本字符串、声明为final的常量值等。
符号引用为类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。

下面是常量池中的项目类型,常量池中的每一项常量都是一个表,表的开始第一位是u1类型的标志位,表示常量属于哪种类型。
这里写图片描述

说明:在常量池中一些符号引用的索引值是指向constant_utf8_info类型的常量。class文件中方法、字段都需要引用constant_utf8_info型常量来描述名称,最大长度为u2,u2能表达的最大值是65535,所以在java程序中变量、方法名不能超过64kb。

5.访问标志

表示类或接口的访问信息,class文件是否为接口,是否定义为public类型,是否声明为final类型等等。

6.类索引、父类索引、接口

类索引、父类索引、接口记录了其全限定名的索引,指向常量池中的constant_class_info,再由constant_class_info指向constant_utf8_info找到对应的类全限定名。
由于一个类可以实现多个接口,因此,class文件中包含多个接口,此时需要一个前置计数器记录接口数量。

7.字段表集合

字段表存储类中的成员变量,包括实例变量和类变量,其结构如下:
这里写图片描述

access_flags:字段的访问标志,字段的类型,是否为public,是否为final,是否为volatile,是否为transient等。

name_index:字段名索引,最终指向constant_utf8_info中的字符串,代表字段的简单名称。

descriptor_index:字段描述符索引,用于描述字段的数据类型。基本数据类型的描述符用大写字母表示,如果字段是对象类型,用大写L表示,如果字段是数组类型,用[表示这是个数组。

attributes_count:属性表长度

attributes:存放字段的额外信息,比如说,如果定义为final类型的字段,初始化时由初始值,初始值存放在CONSTANT_VALUE属性中。

8.方法表集合

方法表与字段表类似,name_index描述方法的简单名,descriptor_index是方法的描述符,描述方法的参数,返回类型。对于方法中的方法体是由attributes中的code属性描述。

9.属性表集合

属性表主要用来描述字段表、方法表以外的一些额外信息

你可能感兴趣的:(jvm)