欢迎您光临本小站。希望您在这里可以找到自己想要的信息。。。

深入理解java虚拟机(四)

java water 2689℃ 0评论

类文件结构

代码编译的结构从本地机器码转变为字节码,是存储格式发展的一小步,确实编程语言发展的一大步

计算机只认识01,我们写的程序需要被编译器翻译成01构成的二进制格式才能被计算机执行。由于虚拟机及建立在虚拟机之上的大量程序语言大量出现,越来越多的程序语言选择了与操作系统和机器指令集无关的,平台中立的格式作为程序编译后的存储格式

无关性的基石

实现语言无关性的基础是虚拟机和字节码存储格式,虚拟机不关心Class的来源是什么语言,只要它符合Class文件应有的结构就可以在Java虚拟机中运行。

Java语言中的各种变量、关键子和运算符合的语义最终都是有多条字节码命令组合而成的,因此字节码命令提供的语义描述能力比Java语言本身更强大。因此,有一些Java语言本身无法有效支持的语言特性并不代表字节码本身无法有效支持,这也为其他语言实现一些有别于Java的语言特性提供了基础。

Class类文件的结构

Class文件是一组以8位字节为基础单位的二进制流,class文件格式采用一种类似于C语言结构体的伪结构来存储,只有两种数据类型:无符号数和表

无符号数:属于基本的数据类型,以u1u2u4u8来分别代表1个字节、2个字节、4个字节、和8个字节的无符号数,可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串

表:是由多个无符号数或其他表作为数据项构成的复合数据类型,所有表都习惯地以“_info”结尾。表用于描述有层次关系的复合结构数据,整个Class文件本质上就是一张表。

无论是无符号数还是表,当需要描述同一类型但数量不一定的多个数据时,经常会使用一个前置的容器计数器加若干个连续的数据项的形式,这时候称这一系列连续的某一类型的数据为某一类型的集合。

Class的机构不像XML等描述语言,由于它没有任何分隔符号

Class类文件的结构

魔数与class文件的版本:class文件的头四个字节称为魔数,它的唯一作用是用于确定这个文件是否为一个能被虚拟机接受的class文件。使用魔数而不是扩展名来进行识别主要是基于安全考虑,扩展名可以随意改动,紧接着魔数的4个字节存储class文件的版本号:第5和第6个字节是次版本号,第7个和8个字节是主版本号

常量池:紧接着主次版本号之后的是常量池入口,常量池是Class文件结构中与其他项目关联最多的数据类型,也是占用class文件空间最大的数据项目之一,同事它还是在class文件中第一个出现的表类型数据项目

常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值,容量计数从1而不是0开始,将0项常量空出来是有特殊考虑的,为了满足后面某些指向常量池的索引值的数据在特订情况下需要表达“不引用 任何一个常量池项目”的意思

主要存放:字面量和符合引用,字面量如文本字符串、被声明为final的常量值。符号引用包括:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。

Java代码在进行JavaC编译的时候,并不像CC++那样有“连接”这个步骤,而是在虚拟机加载Class文件的时候进行动态连接。也就是说,在Class文件中不会保存各个方法和字段的最终内存布局信息,因此这些字段和方法的符号引用不经过转换的话是无法直接被虚拟机使用的。当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析并翻译到具体的内存地址之中。

 

常量池中的每一项常量都是一个表。共有11中结构各不相同的表结构数据。这11中表都有一个共同的特点,就是表开始的第一位是一个u1类型的标志位(tag,取值为112,缺少标志为2的数据类型),代表当前这个常量属于那种常量类型。

专门用于分析Class文件字节码的工具:javap, 使用-verbose参数

访问标志:常量池结束之后,2个字节代表访问标志,用于识别一些类或接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final

类索引、父类索引和接口索引集合 类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的结合

字段表集合:用于描述接口或类中声明的变量。字段包括了类级别变量或实例级变量,不包括在方法内部声明的变量。

“简单名称”、“描述符”及前面出现过多次的“全限定名”这三种特殊字符串的概念

全限定名:把类全名中的“.”替换成“/”而已,为了连续的多个限定名之间不产生混淆,在使用时最后一般加入一个“;”号标识全限定名结束

简单名称:指没有类型和参数修饰的方法或字段名称

描述符:用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值,用描述符来描述方法时,按照先参数列表,后返回值的顺序描述,参数列表按照参数的严格数序放在一组小括号“()”之内。属性表集合用于存储一些额外信息,字段都可以在属性表中描述0至多项额外信息。

方法表集合:方法的定义可以通过访问标志、名称索引、描述符索引表表达清楚,但方法里面的代码去哪里了?方法里的Java代码,经过编译器编译成字节码指令之后,存放在方法属性表集合中一个名为Code的属性里面。

有可能出现由编译器自动添加的方法,最典型的便是类型构造器<clinit>方法和实例构造器<init>方法

属性表集合:Class文件、字段表、方法表中都可以携带自己的属性表集合,以用于描述某些场景专用的信息。属性表集合的限制稍微宽松一些,不再要求各个属性表具有严格的顺序,并且只要不与已有的属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java虚拟机运行时会忽略掉它不认识的属性

Class文件是Java虚拟机执行引擎的数据入口,也是java技术体系的基础支柱之一。了解了Class文件的结果对后面进一步了解虚拟机执行引擎有重要意义

转载请注明:学时网 » 深入理解java虚拟机(四)

喜欢 (0)or分享 (0)

您必须 登录 才能发表评论!