Java学习笔记

《深入理解Java虚拟机》学习笔记(四)(类文件结构)

2017-03-08  本文已影响13人  码梦的一生
图0 Java字节码排列方式

魔数与Class文件的版本

图1 一个class文件的字节码(前8个字节)

Java的版本号是从45开始的,JDK 1.1之后的每个JDK大版本发布主版本号向上加1(JDK 1.0~1.1使用了45.0~45.3的版本号),高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的Class文件,即使文件格式并未发生任何变化,虚拟机也必须拒绝执行超过其版本号的Class文件。

常量池

紧接着主次版本号之后的是常量池入口,常量池可以理解为Class文件之中的资源仓库,它是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一,同时它还是在Class文件中第一个出现的表类型数据项目。

由于常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值(constant_pool_count)。 这个容量计数是从1而不是0开始的。

常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)

常量池中每一项常量都是一个表,在JDK 1.7时共有14种结构各不相同的表结构数据,表开始的第一位是一个u1类型的标志位,代表当前这个常量属于哪种常量类型。

图3 常量池的项目类型

UTF-8缩略编码与普通UTF-8编码的区别:从'\u0001'到'\u007f'之间的字符(相当于1~127的ASCII码)的缩略编码使用一个字节表示,从'\u0080'到'\u07ff'之间的所有字符的缩略编码用两个字节表示从'\u0800'到'\uffff'之间的所有字符的缩略编码就按照普通UTF-8编码规则使用三个字节表示。

访问标志

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

图4 访问标志

类索引、 父类索引与接口索引集合

类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interfaces)是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类的继承关系

类索引、 父类索引和接口索引集合都按顺序排列在访问标志之后

字段表集合

用于描述接口或者类中声明的变量,包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。

图5 字段表结构
描述符

用来描述字段的数据类型、 方法的参数列表(包括数量、 类型以及顺序)和返回值

图6 描述符标识字符含义

用描述符来描述方法时,按照先参数列表,后返回值的顺序描述。参数列表按照参数的严格顺序放在一组小括号“()”之内。 如方法void inc()的描述符为“()V”,方法java.lang.String toString()的描述符为“()Ljava/lang/String;”,方法intindexOf(char[]source,int sourceOffset,int sourceCount,char[]target,int targetOffset,inttargetCount,int fromIndex)的描述符为“([CII[CIII)I”。

字段表都包含的固定数据项目到descriptor_index为止就结束了,不过在descriptor_index之后跟随着一个属性表集合用于存储一些额外的信息,字段都可以在属性表中描述零至多项的额外信息。

字段表集合中不会列出从超类或者父接口中继承而来的字段,但有可能列出原本Java代码之中不存在的字段,譬如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。

方法表集合

Class文件存储格式中对方法的描述与对字段的描述几乎采用了完全一致的方式,方法表的结构如同字段表一样,依次包括了访问标志(access_flags)、 名称索引(name_index)、 描述符索引(descriptor_index)、 属性表集合(attributes)几项

方法里的Java代码,经过编译器编译成字节码指令后,存放在方法属性表集合中一个名为“Code”的属性里面

如果父类方法在子类中没有被重写(Override),方法表集合中就不会出现来自父类的方法信息。但同样的,有可能会出现由编译器自动添加的方法,最典型的便是类构造器“<clinit>”方法和实例构造器“<init>”方法。

在Java语言中,要重载(Overload)一个方法,除了要与原方法具有相同的简单名称之外,还要求必须拥有一个与原方法不同的特征签名

属性表集合

上一篇 下一篇

猜你喜欢

热点阅读