<!----><!----><!----> <!----><!----><!---->
<!---->1) <!---->Fields_count 和 fields
紧接着 interfaces 后面的是对该类或者接口中所生命的字段的描述。首先是计数 fields_count ,它是类变量和实例变量的字段的数量总和。在这个计数后面有相应数目个 field_info 表。此表包含了字段的名字、描述符和修饰符。如果该字段被声明为 final , field_info 还会展示其常量值。
<!----><!----> <!---->
图 2 : field_info 表的格式
自上而下分别为:访问标志,简单名称(非全限定名),字段描述符,属性。字段描述符即该字段的型别。
<!---->2) Methods_count 和 methods <!---->
方法表与方法表计数。方法表的格式与 field_info 类似,区别在于其描述的是方法。故不再赘述。
<!---->3) Attributes_count 和 attributes <!---->
Java 虚拟机实现定义了两种属性 ----SourceCode 和 InnerClasses ,它们出现在 ClassFile 表中的属性列表中。
Class 的生命周期
Java 虚拟机通过装载、连接和初始化一个 java 类型,使该类型可以被正在运行的 java 程序所使用。其中,装载就是把二进制形式的 java 类型读入 java 虚拟机中;而连接就是把这种已经读入虚拟机的二进制形式的类型数据合并到虚拟机的运行时状态中。连接阶段分为三个子步骤 ----- 验证、准备、解析。“验证”确保了 java 类型数据格式正确并且适于 java 虚拟机的使用。而“准备”步骤则负责为该类型分配它所需的内存,比如为它的类变量分配内存。“解析”步骤则负责把常量池中的符号引用转换为直接引用。
<!----><!----> <!---->
图 3 :类型生命周期的开始
装载
要装载一个类型, java 虚拟机必须:
<!---->l <!---->通过该类型的完全限定名,产生一个代表该类型的二进制数据流
<!---->l <!---->解析这个二进制数据流为方法去内的内部数据结构
<!---->l <!---->创建一个俄表示该类型的 java.lang.Class 类的实例
装载步骤的最终产品就是一个 java.lang.Class 的实例对象,而这个对象就是该类型在虚拟机中的“注册”,要访问该类型的信息,程序就要调用该类型对应的 class 实例对象的方法。
所有类都由类装载器载入,载入内存中的类对应一个 java.lang.Class 实例。存在一个 Bootstrap Loader (以下简称为 BL ),由 C++ 写成,负责在虚拟机启动后一次性加载 Java 基础类库中的所有类。其他的类装载器由 java 写成,都是 java.lang.ClassLoader 的子类。除 BL 之外的所有类装载器都有一个 parent 属性,指向其父装载器。
用户自定义的类装载器是 java.lang.ClassLoader 的子类的实例,它以定制的方式装入类。
<!---->l <!---->装载一个类时,首先要装载该类的基类及其接口
<!---->l <!---->Java 基础类由 BL 在虚拟机启动时一次性载入
<!---->l <!---->包含 main() 的入口类由 AL 的 loadClass() 方法载入。
<!---->l <!----> 由 new 关键字创建一个类的实例。该类由运行时刻包含该 new 语句的类实例的类装载器( ClassLoader.getCallerClassLoader() )的 loadClass() 方法载入
连接
验证
连接过程的第一步是验证 - 确认类型符合 JAVA 语言的语义,并且它不会危及虚拟机的完整性。确保每个 final 类不含有子类, final 方法不能被覆盖,以及常量池中所有的域引用和方法引用有有效的名字和类型描述符号。
准备
JAVA 虚拟机为类变量分配内存,设置默认初始值(非初始化时的默认值)。
解析
初始化
在初始化阶段, Java 虚拟机设计者需要将类变量赋予正确的初始值。 <clinit> 方法:类变量初始化语句与静态初始化块