Java中类的加载

Java中class的加载,这里的加载值指的是一个宏观的过程,其中又分为几个小的过程:加载(Loading)、链接(Linking)、初始化(Initialization)

class java 加载方式 java class类加载过程_加载

加载(Loading)

  1. 找到文件,class文件是一个字节流文件
  2. 将里面的静态存储结构转换为方法区(JDK7及之前叫做Perm Gen,JDK8及之后叫做Meta space)的运行时数据结构
  3. 在内存中生成一个代表当前加载类的java.lang.Class对象,作为访问入口,这个Class相当于一个模板,创建Class的Object时,就是从这个模板创建

链接(Linking)

链接又分为了三个小阶段:验证(Verification)、准备(Preparation)、解析(Resolution)

验证(Verification)

目的是确保Class文件的字节流中包含的信息符合当前的Java虚拟机要求,保证被加载类的正确性并不会危机自身虚拟机的安全。
包括四种验证方式:

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符号引用验证

准备(Preparation)

  • 为类变量分配内存,并设置初始值,叫做零值,基本类型如int设置为0,boolean类型设置为false等等,引用类型则设置为null。这里的操作不会作用于常量(static final),因为常量在编译时会确定内存大小(因为是常量嘛,以后不会改变了),这里只是将真正的值赋给它。

比如

private static final String msg = "Hello world.";

这里是直接将"Hello world."msg,而不是先给一个null后面再赋值。

  • 此时肯定不会为实例的变量分配内存和初始值,因为此时并没有到创建对象这个环节。

解析(Resolution)

  • 将常量池里面的符号引用转换为直接引用
  • 其他的放张图吧,不想敲了

初始化(Initialization)

  • 初始化就是执行类的clinit方法,这个方法是在javac编译的时候自动收集类的信息自动生成的,一般收集的是类变量和静态代码块,然后按照顺序执行

如何理解按照顺序执行呢?比如有以下代码:

public class ClinitTest {
    static int a = 1;
    
    static {
        a = 2;
        b = 20;
    }

    static int b = 10;

    public static void main(String[] args) {
        System.out.println(a); // 2
        System.out.println(b); // 10
        // 打印结果分别是 2 和 10
    }
}
  • 在执行类的clinit方法时,如果当前类存在父类,那么会先执行父类的clinit方法9(如果有)
  • 虚拟机会保证一个类的clinit只执行一次(加锁),即使有多个线程同时做初始化操作