[2025.1.20 JavaSE学习]类加载
类加载
一、基本说明
反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载
- 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
- 动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性
- 静态加载例子:
Scanner scanner = new Scanner(System.in);
String key = scanner.next();
switch(key){
case "1":
Dog dog = new Dog();
dog.method();
break;
case "2":
break;
}
代码虽然不一定会用到Dog类,但是会静态记载,报错找不到类"Dog",一定要编写这个类的定义
- 动态加载例子:
Scanner scanner = new Scanner(System.in);
String key = scanner.next();
switch(key){
case "1":
Dog dog = new Dog();
dog.method();
break;
case "2":
Class cls = Class.forName("Person");//加载Person类,但是编译的时候不会加载
Object o = cls.newInstance();
Method m = cls.getMethod("method_");
m.invoke(o);
break;
}
二、类加载时机
- 创建对象时(new)
- 子类被加载时
- 调用类中的静态成员时
- 通过反射
三、类加载流程
- 类加载流程图如下:

- 1、加载阶段
- 将类的class文件读入内存,并为之创建一个java.lang.Class对象,此过程由类加载器完成
- 详解:JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能时jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
- 将类的class文件读入内存,并为之创建一个java.lang.Class对象,此过程由类加载器完成
- 2、连接阶段
- 验证阶段:对文件安全性进行验证
- 详解:目的是为了确保class文件的字节流中包含的信息符合当前JVM要求,并且不会危害JVM自身的安全,包括:文件格式验证(以魔数 oxcafebabe开头为安全)、元数据验证、字节码验证和符号引用验证
- 可以使用 -Xverify:none参数来关闭大部分的类验证措施,缩短JVM加载时间
- 准备阶段:进行默认初始化,分配空间
- 详解:JVM会在该阶段对静态变量分配内存并初始化(对应数据类型的默认初始值,如0、0L、null、false等),这些变量所使用的内存都将在方法区进行分配
- 验证阶段:对文件安全性进行验证
public int n1 = 10;
public static int n2 = 20;
public static final int n3 = 30;
//准备阶段
//n1是实例属性,不是静态变量,因此在准备阶段,不会分配内存
//n2是静态变量,分配内存,在该阶段默认初始化为0,而不是20
//n3 static final是常量,和静态变量不一样一旦赋值就不变,在该阶段直接为30
- 解析阶段:把符号引用转为直接引用
- 最后将类的二进制数据合并到JRE中
- 关于两种引用的gpt解释如下:
1. 符号引用(Symbolic Reference)
- 定义:
- 符号引用是一种抽象引用,用于描述目标(如类、方法、字段)的逻辑信息。
- 它不涉及具体的内存地址或偏移量,而是通过符号(如类名、方法名、字段名)来引用目标。
- 特点:
- 与具体的内存布局无关。
- 是一种逻辑描述,独立于 JVM 的实现。
- 示例:
- 类符号引用:
java/lang/Object - 方法符号引用:
java/lang/Object.toString()Ljava/lang/String; - 字段符号引用:
java/lang/System.out:Ljava/io/PrintStream;
- 类符号引用:
- 存储位置:
- 符号引用存储在
.class文件的常量池中。
- 符号引用存储在
2. 直接引用(Direct Reference)
- 定义:
- 直接引用是一种具体引用,指向目标在内存中的实际地址或偏移量。
- 它可以直接用于访问目标(如调用方法、访问字段)。
- 特点:
- 与具体的内存布局相关。
- 是一种物理描述,依赖于 JVM 的实现。
- 示例:
- 类直接引用:指向方法区中类元数据的指针。
- 方法直接引用:指向方法代码的指针。
- 字段直接引用:指向字段内存地址的指针。
- 生成时机:
- 在类加载的解析阶段,符号引用会被转换为直接引用。
- 3、初始化阶段
- JVM负责对类进行初始化,这里主要是指静态成员(因为是类加载阶段)
- 详解:到初始化阶段,才开始真正执行类中定义的Java程序代码,此阶段是执行< clinit >方法的过程
- < clinit >方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并
- JVM会保证一个类的< clinit >()方法在多线程环境中被正确地加锁、同步,如果多个线程同时初始化一个类,那么只会有一个线程去执行这个类的< clinit >方法,其他线程都需要阻塞等待,直到活动线程执行< clinit >()方法完毕
- JVM负责对类进行初始化,这里主要是指静态成员(因为是类加载阶段)
- 前两个阶段都是JVM进行指定,最后一个阶段可由程序员进行决定

浙公网安备 33010602011771号