类装载过程由JVM类装载子系统负责,主要包括一下三个步骤:
1)装载:查找并装载类型的二进制数据到虚拟机中
1.通过某些途径,产生一个代表该类型的二进制数据流
2.解析二进制数据流为方法区的内部数据结构
3.在堆中创建一个表示该类型的Class实例(装载步骤的最终产品)
注意:Java虚拟机规范允许类装载器缓存Java类型的二进制表现形式,如果预装载出错,则要等待该类被主动使用时抛出LinkageError的子类的异常
2)连接:
1.验证 确保导入的类格式正确
检查final类不能有子类,final方法不能被覆盖,常量池检查,字节码完整性检查...
注意:Java虚拟机设计者可以决定如何及时验证类型。Java虚拟机规范列出了虚拟机可以抛出的异常以及在何种条件下必须抛出它们
2.准备 为类变量分配内存,设置默认初始值
3.解析 把类型中的符号引用转换为直接引用(也可能推迟到真正需要使用某个符号引用时再去解析它)
在类型的常量池中寻找类,接口,字段和方法的符号引用,把类型中的符号引用转换为直接引用
3)初始化:把类变量初始化为正确的初始值
1.如果类存在直接超类,且直接超类还没有初始化,则先初始化直接超类
2.如果类存在一个类初始化方法(“”,并不是所有的类都存在这个方法,如果一个类没有类变量也没有静态初始化语句,就没有该方法),就执行它
所有的类变量初始化语句和类型的静态初始化器都被Java编译器收集在一起,放到一个特殊的方法(“”)中,称为类初始化方法,此方法只能被Java虚拟机调用
所有的Java虚拟机实现必须在每个类或接口首次主动使用时初始化。有以下六种
1)当创建某个类的新实例时,或者在字节码中执行new指令,或者通过不明确的创建、反射、克隆或者反序列化时。
2)当调用某个类的静态方法时(即在字节码中执行invokestatic指令)
3)当使用某个类或接口的静态字段,或者对该字段赋值时(即在字节码中执行getstatic或putstatic指令时,用final修饰的静态字段除外,它被初始化为一个编译时的常量表达式)
4)当调用Java API的某些反射方法时,比如类Class中的方法或者java.lang.reflect包中的类的方法
5)当初始化某个类的子类时(除接口外)
6)当虚拟机启动时某个被表明为启动类(含有main方法)的类
除以上六种情形外,所有其它使用Java类型的方式都是被动使用,都不会导致Java类型的初始化