Class类加载过程
类加载器子系统
类加载器子系统只负责加载class文件,class文件的文件头有文件标识。
ClassLoader只负责class的加载,至于是否可以运行,由Execution Engine(执行引起)决定。
加载类的信息存放于方法区中。除了类的信息外,方法区中还会存放运行时常量池的信息,可能还包含字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)。
加载class类时:
-
class file 存在硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载到JVM中来根据该文件实例化出n个一模一样的实例。
-
class file 加载到JVM中,被称为DNA元数据模板,存放在方法区。
-
在 .class 文件–> JVM --> 最终成为元数据模板,此过程就需要一个运输工具(类加载器 classloader),扮演一个快递员的角色
1. 加载
将class文件加载至java虚拟机,并存储在方法区。方法区存储类信息、常量、静态变量。
2. 连接-验证
确保加载进来的class文件包含的信息是否符合java虚拟机的要求。是否合法、是否安全。
验证项目包括:文件格式验证、元数据验证、字节码验证、符号引用验证。
3. 连接-准备
为类变量分配内存,并设置类变量的初始值,即零值。
- 进行内存分配的包括类变量(static 修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在java堆中。
- 这里不包含用final修饰的static,因为final在编译的时候就被分配了,准备阶段会显式初始化;
- 其次是这里所说的初始值“通常情况”下是数据类型的零值(如0、0L、null、false等)。
4. 连接-解析
将变量池里符号引用转为直接引用。
- 符号引用就是一组符号用来描述所引用的目标。符号引用的字面量形式明确定义在《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
- 解析动作主要针对类或接口、类方法、方法接口、方法类型等。对应常量池中的CONSTANT_Class_info、 CONSTANT_Fieldref_info、 CONSTANT_Methodref info等。
5. 初始化
初始化类变量、静态语句块,执行类构造器方法 ()的过程 。
- 该方法不需要被定义,是javac编译器自动收集类中所有变量的赋值动作和静态代码块中的语句合并而来
- 构造器方法中按语句在源文件中出现的顺序执行
- ()不同于类的构造器(类的构造器在虚拟机视角下是())
- 若该类具有父类,JVM会保证子类的 ()执行前,父类的 ()已经执行完毕
- 虚拟机必须保证一个类的 ()方法在多线程下被同步加锁
在以下四种情况下初始化过程会被触发执行:
- 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需先触发其初始化;
- 使用java.lang.reflect包的方法对类进行反射调用的时候;
- 当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先出发其父类的初始化;
ct包的方法对类进行反射调用的时候; - 当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先出发其父类的初始化;
- jvm启动时,用户指定一个执行的主类(包含main方法的那个类),虚拟机会先初始化这个类