类加载过程
加载---》连接(验证,准备,解析)---》初始化。从 class 文件到内存中的类,按先后顺序需要经过加载、链接以及初始化三大步骤。其中,链接过程中同样需要验证;而内存中的类没有经过初始化,同样不能使用,初始化不是必须的。
加载
类将.class文件加载至元空间后,会在堆中创建一个Java.lang.Class对象,用来封装类位于方法区内的数据结构,该Class对象是在加载类的过程中创建的,每个类都对应有一个Class类型的对象,Class类的构造方法是私有的,只有JVM能够创建。因此Class对象是反射的入口,使用该对象就可以获得目标类所关联的.class文件中具体的数据结构。
类加载的最终产物就是位于堆中的Class对象,该对象封装了类在方法区中的数据结构,并且向用户提供了访问方法区数据结构的接口,即Java反射的接口。
总之就是文件的信息,一些字节码文件都在元空间之中,一些对象的信息都在堆区之中。
链接
验证
有效性的检查,能不能用
准备
准备阶段主要是在元空间(方法区)为加载类的静态字段分配内存,设置变量的初始化值。
解析
解析阶段则主要将符号引用解析为实际的引用。如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载。
-主动引用:new一个对象。调用类的静态成员和静态方法(除了final常量)。使用java.lang.reflect包的方法进行反射调用。main方法所在的类。
-被动引用:引用常量。当访问一个静态域。通过数组定义类引用,不会触发此类的初始化。引用常量不会触发类的初始化。
初始化
类的初始化只有一次,类的初始化是不同于对象的初始化。
类加载的最后一步是初始化,如果直接赋值的静态字段被 final 所修饰,并且它的类型是基本类型或字符串时,该字段便会被 Java 编译器标记成常量值(ConstantValue)。初始化会为类的常量赋值,以及执行静态代码块中的方法。
这一阶段可以执行类的一些静态代码块。初始化是非必要的,例如我的main根本没有用到一个类或者其字类的方法,这个类是不需要初始化的,即使初始化,也会被回收。
以下是类初始话的触发条件,其实就是用到,或者再可预见的未来会被用到就初始化。
当虚拟机启动时,初始化用户指定的主类;
当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;
当遇到调用静态方法的指令时,初始化该静态方法所在的类;
当遇到访问静态字段的指令时,初始化该静态字段所在的类;
子类的初始化会触发父类的初始化;
如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;
使用反射 API 对某个类进行反射调用时,初始化这个类;
网友评论