【1】类加载的时机
类的生命周期如下图所示;
类初始化开始的时机(主动引用):
1. 遇到 new,getstatic,putstatic,invokestatic 字节码时,需要初始化;
2. 使用 java.lang.reflect 包的方法对类进行反射调用的时,需要初始化;
3. 初始化类时,若该类的父类未初始化则先触发其父类的初始化;(注:对于类初始化要求其父类全部都已经初始化,对于接口初始化只有当真正用到父接口时才会对父接口初始化);
4. 虚拟机启动时,需要指定待执行的主类,虚拟机优先初始化该类;
5. JDK 动态语言支持时,若 java.lang.invoke.MethodHandle 实例最终解析结果是 REF_getStatic,REF_putStatic,REF_invokeStatic 的方法句柄,并且方法句柄对应的类没有初始化,则触发初始化;
被动引用(引用类但不会触发初始化处理),场景:
1. 通过子类引用父类的静态字段,不会导致子类初始化,对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过子类引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化;
2. 通过数组定义引用类,不会触发此类的初始化;
3. 常量在编译阶段会存入调用常量类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化;
【2】类加载的过程
加载阶段
主要任务:1. 通过类的全限定名获取此类的二进制字节流;2. 将该字节流所代表的静态存储结构转化为方法区的运行时数据结构;3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区该类的各种数据的访问入口;
数组的特殊性
数组类本身不通过类加载器创建,其由 Java 虚拟机直接创建,数组的元素类型需要类加载器创建;
数组类创建过程规则
1. 数组的组件类型为引用类型,递归加载该组件类型,数组在加载该组件类型的类加载器的类名称空间上被标识;
2. 数组的组件类型不是引用类型,Java虚拟机会将数组标记为与引导类加载器关联;
3. 数组类的可见性与其组件类型的可见性一致,若组件类型不是引用类型,则数组类的可见性默认为public;
验证阶段
目的:确保Class文件的字节流中包含的信息符合当前虚拟机的要求;
阶段性检验动作:1. 文件格式验证;2. 元数据验证;3. 字节码验证;4. 符号引用验证;
准备阶段
作用:正式为类变量分配内存并设置类变量初始值,该阶段变量所用的内存将在方法区中进行分配,该阶段类变量初始值为零;当类字段的字段属性存在ConstantValue属性,则准备阶段变量将初始化为ConstantValue属性所指定的值;
解析阶段
作用:将常量池内的符号引用替换为直接引用;
符号引用,以一组符号描述所引用的目标,符号可以是任意形式的字面量,只要使用时能够无歧义地定位到目标即可;
直接引用,直接指向目标的指针、相对偏移量、间接定位到目标的句柄,直接引用与虚拟机实现的内存相关;
解析发生时机,发生在执行 anewarray,checkcast,getfield,getstatic,instanceof,invokedynamic,invokeinterface,invokespecial,invokestatic,invokevirtual,ldc,ldc_w,multianewarray,new,putfield,putstatic字节指令之前;
解析针对的符号与常量类型
类或接口 | 字段 | 类方法 | 接口方法 | 方法类型 | 方法句柄 | 调用点限定符 |
CONSTANT_ Class_info |
CONSTANT_ Fieldref_info |
CONSTANT_ Methodref_info |
CONSTANT_ InterfaceMethodref_info |
CONSTANT_ MethodType_info |
CONSTANT_ MethodHandle_info |
CONSTANT_ InvokeDynamic_info |
D:当前代码所处的类;N:从未解析过的符号引用;C:类或接口的直接引用;
类或接口解析步骤:
字段解析步骤:
类方法解析步骤:
接口方法解析步骤:
初始化阶段
作用:根据程序员通过程序制定的主观计划初始化类变量和其他资源,即初始化阶段是执行类构造器
1.
2. 虚拟机保证在子类的
3. 父类中定义的静态语句块要优先于子类的变量赋值操作;
4.
5. 接口与类一样都会生成
6. 虚拟机保证一个类的
【3】类加载器
作用:通过一个类的全限定名来获取描述此类的二进制字节流;
类与类加载器:对于任意的一个类,需要由加载它的类加载器和这个类本身一同确定其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间;
双亲委派模型:
类加载器的分类,1. 启动类加载器,负责将存放在
类加载器之间的层次结构(双亲委派模型),双亲委派模型要求除顶层的启动类加载器之外,其余的类加载器都应当有自己的父类加载器,子类加载器以组合的方式复用父加载器的代码;
双亲委派模型优点:Java类随着它的类加载器一起具备了一种带有优先级的层次关系;
参考致谢
本博客为博主的学习实践总结,并参考了众多博主的博文,在此表示感谢,博主若有不足之处,请批评指正。
【1】深入理解 Java 虚拟机 JVM 高级特性与最佳实践
【2】Java虚拟机类加载机制和双亲委派模型