Class 加载过程
类装载的条件Class 只有被利用到的时候才会被装载,一个类或接口在第一次主动利用时,必须要进行初始化。主动利用包括以下几种情形:
当创建一个类的实例时,比如利用new关键字,或者通过反射、克隆、反序列化;当调用类的静态方法时,也便是利用了 invokestatic 指令;当利用类或接口的静态字段(非 final 的常量),比如利用 getstatic 或 putstatic 指令;当利用 java.lang.reflect 包中的方法,反射类的方法时;当初始化子类时,首先要先初始化父类;主函数的入口(main() 函数);下面看一个被动引用的例子:
/ 被动利用类字段演示:通过子类引用父类的静态字段,不会导致子类初始化 @author xuefeihu /public class SuperClass {static {System.out.println(\"大众SuperClass init!\公众);}public static int value = 123;}public class SubClass extends SuperClass {static {System.out.println(\"大众SubClass init!\"大众);}}public class NotInitialization {public static void main(String[] args) {System.out.println(SubClass.value);}}
运行后的结果为:
SuperClass init!123
下面看一个被动引用的例子:
// 加载Child之前会去先加载Parentpublic class Parent {static {System.out.println(\"大众Parent init\"大众);}}public class Child extends Parent {static {System.out.println(\"大众Child init\"大众);}}public class InitMain {public static void main(String[] args) {Child c = new Child();}}
实行结果如下:
Parent initChild init加载
在类加载阶段紧张完成以下三件事情:① 通过此类的全限定名来获取此类的二进制字节流。② 将这个字节流所代表的静态存储构造转化为方法区的运行时数据构造。③ 在 java堆中天生对应的 java.lang.Class 工具。java 字节码的获取办法可以有以下几种办法:
从 ZIP包中获取(如 jar、ear、war 等)从网络中获取运行时动态天生,利用最多的便是动态代理(如:JDK动态代理、CGLIB动态代理)其他文件天生(如JSP编译天生对应的class文件)从数据库中读取(相对较少)验证验证的目的是担保字节码文件是精确的。验证的办法紧张有以下几种:① 文件格式的验证;② 元数据验证;③ 字节码验证(很繁芜);④ 符号引用验证
文件格式的验证① 是否以 0XCAFEBABY 开头
② 主次版本号是否在当前 JVM 处理范围之内
③ 常量池中是否有不被支持的常量
......
元数据验证① 是否有父类
② 继续了 final 类?
③ 非抽象类实现了所有的抽象方法
......
字节码验证① 运行检讨
② 栈数据类型和操作码数据参数吻合
③ 跳转指令指定到合理的位置
......
符号引用验证① 符号引用中通过字符串描述的权限定名是否能找到对应的类
② 类中是否存在符合方法的字段描述以及大略名称所描述的方法和字段
③ 符号引用中的类、字段、方法的访问性是否可以被当前类访问
......
准备准备阶段便是为 static 类型的变量分配初始值(如int类型的初始值为0),须要把稳的是当变量类型为 static final 时,准备阶段就将其赋值为终极的值。
解析JVM 将常量池内的符号引用(与 JVM 无关)转化为直接引用(与 JVM 干系)。解析动作紧张针对付类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用。
初始化初始化阶段包括实行布局器,个中包括了 static 变量赋值语句和 static{} 静态块;子类的调用之前担保父类的被调用;还有一点便是是线程安全的。
参考:《深入理解Java虚拟机》