美文网首页
类加载流程

类加载流程

作者: sunpy | 来源:发表于2022-04-27 23:29 被阅读0次

类加载流程


加载阶段


加载阶段分为 虚拟机启动加载和运行时期加载。

  1. 虚拟机启动加载:
    加载JAVA_HOME/lib/下的rt.jar下的.class文件
    使用-XX:+TraceClassLoading查看加载类信息。
  2. 运行时期加载:
  • 通过一个类的全限定名(包名+类名)来获取该class文件的二进制字节流。
  • 将字节流的静态存储结构转化为方法区的运行时数据结构。
  • 为上面的class文件,在堆中生成一个java.lang.Class对象对该类的数据访问入口。
  1. 什么时候主动使用会加载?
  • 创建类实例时,如使用new关键字、反射、克隆、反序列化
  • 调用类静态方法,使用字节码invokestatic指令
  • 使用类或接口静态字段时(final修饰除外),使用getstatic或者putstatic指令。
  • 使用java.lang.reflect包中的方法反射类的方法。
  • 初始化子类,先初始化父类。
  • 启动虚拟机,含main方法的那个类。
例1:初始化子类,引发虚拟机先初始化父类
public class FatherClazz {
    static {
        System.out.println("FatherClazz初始化");
    }
}
public class SonClazz extends FatherClazz {
    static {
        System.out.println("SonClazz初始化");
    }
}
public class ClassLoadTest {

    public static void main(String[] args) {
        SonClazz sonClazz = new SonClazz();
    }
}
例2:使用类静态字段
public class FatherClazz {
    static {
        System.out.println("FatherClazz初始化");
    }

    public static int fv = 100;
}
public class ClassLoadTest {

    public static void main(String[] args) {
        System.out.println(SonClazz.fv);
    }
}
例3:数组类初始化,首次初始化数组元素时加载
public static void main(String[] args) {
        FatherClazz[] arr = new FatherClazz[5];

        System.out.println("start 1");
        arr[0] = null;
        System.out.println("start 2");

        arr[0] = new FatherClazz();
        System.out.println("start 3");
    }
例4:final修饰的常量所在类不会被加载
public class FatherClazz {
    static {
        System.out.println("FatherClazz初始化");
    }

    public static final int fv = 100;
}
public class ClassLoadTest {

    public static void main(String[] args) {
        System.out.println(FatherClazz.fv);
    }
}

连接阶段

  • 验证过程:
    这个阶段主要是验证被加载的类是否正确。目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
    流程:文件格式验证、元数据验证、字节码验证、符号引用验证
  • 准备过程:
    该阶段就是正式为类变量分配内存并设置类变量的初始值,注意类变量使用的内存在方法区上分配。(类变量是static修饰的变量,不包括实例变量,实例变量将会在对象实例化的时候随着对象一起分配在Java堆上)。
  • 解析过程:
    该阶段就是将jvm中常量池内的符合引用替换为直接引用的过程。符号引用、直接引用

初始化阶段

初始化阶段做的事就是执行类的初始化方法<clinit>,在我看来这个标识就是类构造器。方法<clinit>是由编译器自动生成的。就是将static变量赋值指定的值并且static静态代码块中赋值指定值。赋值指定值按顺序来。

public class SonClazz extends FatherClazz {
    public static int sv = fv;
}

public class ClassLoadTest {

    public static void main(String[] args) {
        System.out.println(SonClazz.sv);
    }
}
public class FatherClazz {

    public static int fv = 100;

    static {
        fv = 200;
    }
}
public class FatherClazz {

    static {
        fv = 200;
    }

    public static int fv = 100;
}
参考:《深入理解java虚拟机》

相关文章

网友评论

      本文标题:类加载流程

      本文链接:https://www.haomeiwen.com/subject/gkvqyqtx.html