了解类加载的进阶解过程,有利于在类初始化时进行一些功能操作; 本文全面讲解类加载过程; 从类被加载到虚拟机内存中开始,类加到卸载出内存为止,进阶解它的深载机制整个生命周期分为7个阶段,加载(Loading)、入理验证(Verification)、类加准备(Preparation)、进阶解解析(Resolution)、深载机制初始化(Initialization)、入理使用(Using)、类加卸载(Unloading); 其中验证、进阶解准备、深载机制解析三个部分统称为连接; 类加载的全过程:加载、验证、准备、解析和初始化五个阶段所执行的具体操作 1.1、这在个阶段,虚拟机要做的事情有如下三个: 通过一个类的全限定名来获取定义这个类的二进制字节流; 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构; 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口; 这里的二进制字节流并不一定要从Class文件获取,只要一段二进制字节流符合Class文件的规范,都可以当做一个Class文件,例如我们可以从jar包中获取,云南idc服务商从网络中获取,运行时生成等,总之获取Class文件的方式非常多。 1.2、这里需要注意的是通过一个类的全限定名来获取定义这个类的二进制字节流的动作是有类加载器完成的,对于非数组类的加载,我们可以通过自定义类加载器加载来进行控制。对于数组类就不行,因为它不是通过类加载器创建的,而是由Java虚拟机直接创建的; 但数组类和非数组类也有很大的联系,毕竟组成数组的元素就是非数组类(对于一维数组来说,而对于多维数组来说,可以递归加载),非数组类的创建需要类加载器完成。加载创建一个数组类的过程如下: 准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这个阶段中需要注意两点,首先,这个时候进行内存分配的仅包括类变量(被static修饰的变量)而不包括实例变量,实例变量就在对象实例化时随着对象一起分配在Java堆中,其次,这里所说的初始值通常是数据类型的零值; 下面是四中符号符号引用的解析过程: (1) 类或接口的解析 假设当前代码处于类D中,如果要把一个从未解析过的符号引用N解析为一个类或接口C的直接引用,虚拟机将经历如下的过程: (2)字段解析 要解析一个未被解析过的字段符号引用,首先将会对字段表内class_index项中索引的CONSTANT_Class_info符号引用进行解析,也就是字段所属的类或借口的符号引用。如果解析这个类或接口时发生异常,都会导致解析字段的失败。如果解析成功,才会继续解析这个字段。具体的规则如下: (3)类方法解析 类方法解析的第一个步骤和字段解析一样,也需要先解析出类方法表的class_index项中索引的方法所属的类或接口的符号引用,如果解析成功,按照如下步骤继续(同样以C来表示这个类): (4)接口方法解析 接口方法也要解析接口方法表的class_index所属的类或接口引用,如果解析成功,用C表示这个类或接口,虚拟机按照如下的规则搜索: 类初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制。到了初始化阶段,才真正开始执行类中定义的Java程序。 前面已经知道,在准备阶段变量已经赋值过一次系统初始值了,而在初始化阶段,则会根据程序员通过程序制定的主观计划去初始化类变量和其它内容。即,初始化阶段是执行类构造器<Test>()方法的过程。下面是<Test>()方法的特点: 类加载这类的文章会陆续出几篇,希望大家喜欢! 本文转载自微信公众号「Android开发编程」前言
一、深载机制类加载介绍
1、入理类加载生命周期
2、入理类加载的过程
类加载的过程包括了加载、验证、准备、解析、初始化五个阶段; 在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的亿华云运行时绑定(也成为动态绑定或晚期绑定); 另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段; 二、类加载过程详解
1、加载阶段
2、验证阶段
验证的目的是为了确保Class文件中的字节流包含的信息符合当前虚拟机的要求,而且不会危害虚拟机自身的安全。不同的虚拟机对类验证的实现可能会有所不同,但大致都会完成以下四个阶段的验证:文件格式的验证、元数据的验证、字节码验证和符号引用验证; 文件格式的验证:验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,该验证的主要目的是保证输入的字节流能正确地解析并存储于方法区之内。经过该阶段的验证后,字节流才会进入内存的方法区中进行存储,后面的三个验证都是基于方法区的存储结构进行的; 元数据验证:对类的元数据信息进行语义校验(其实就是对类中的各数据类型进行语法校验),保证不存在不符合Java语法规范的元数据信息; 字节码验证:该阶段验证的主要工作是进行数据流和控制流分析,对类的方法体进行校验分析,以保证被校验的类的方法在运行时不会做出危害虚拟机安全的行为; 符号引用验证:这是最后一个阶段的验证,它发生在虚拟机将符号引用转化为直接引用的时候(解析阶段中发生该转化,后面会有讲解),主要是对类自身以外的信息(常量池中的各种符号引用)进行匹配性的校验; 3、准备阶段
4、解析阶段
解析阶段是虚拟机将常量池中的符号引用转化为直接引用的过程。在Class类文件结构一文中已经比较过了符号引用和直接引用的区别和关联,这里不再赘述。前面说解析阶段可能开始于初始化之前,也可能在初始化之后开始,虚拟机会根据需要来判断,到底是在类被加载器加载时就对常量池中的符号引用进行解析(初始化之前),还是等到一个符号引用将要被使用前才去解析它(初始化之后); 对同一个符号引用进行多次解析请求时很常见的事情,虚拟机实现可能会对第一次解析的结果进行缓存(在运行时常量池中记录直接引用,并把常量标示为已解析状态),从而避免解析动作重复进行; 解析动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行,分别对应于常量池中的CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info四种常量类型; 5、初始化阶段
总结