/**
* 类加载过程(Class Loading Process)
*
* 类加载过程是JVM将类的字节码文件加载到内存并形成可以被Java程序使用的类型的过程。
* 整个类加载过程分为加载、连接(验证、准备、解析)和初始化三个主要阶段。
*
* 图形说明:
* +-------------------+
* | 类加载过程 |
* +-------------------+
* |
* v
* +-------------------+
* | 1. 加载(Loading) |
* +-------------------+
* |
* v
* +-------------------+
* | 2. 连接(Linking) |
* | 2.1 验证 |
* | 2.2 准备 |
* | 2.3 解析 |
* +-------------------+
* |
* v
* +-------------------+
* | 3. 初始化 |
* | (Initialization) |
* +-------------------+
* |
* v
* +-------------------+
* | 4. 使用(Using) |
* +-------------------+
* |
* v
* +-------------------+
* | 5. 卸载(Unloading)|
* +-------------------+
*/
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Field;
import java.security.ProtectionDomain;
public class ClassLoadingProcess {
// 静态变量,在准备阶段会被赋予默认值0
private static int staticVar = 100;
// 常量,在编译时就确定值
private static final String CONSTANT = "Constant Value";
// 静态代码块,在类初始化阶段执行
static {
System.out.println("静态代码块执行,staticVar = " + staticVar);
staticVar = 200;
System.out.println("静态代码块执行完毕,staticVar = " + staticVar);
}
public static void main(String[] args) {
// 演示类加载过程
demonstrateClassLoading();
// 演示类加载的触发时机
demonstrateClassLoadingTriggers();
// 演示类加载的各个阶段
demonstrateClassLoadingStages();
// 演示类加载的特殊情况
demonstrateSpecialCases();
}
/**
* 演示类加载过程
*/
private static void demonstrateClassLoading() {
System.out.println("=== 演示类加载过程 ===");
System.out.println("当前类已经被加载,静态变量值: " + staticVar);
// 主动加载一个类
System.out.println("\n主动加载DemoClass类:");
try {
// 使用Class.forName()加载类,会触发类的初始化
Class<?> clazz = Class.forName("DemoClass");
System.out.println("成功加载类: " + clazz.getName());
// 创建实例
Object instance = clazz.newInstance();
System.out.println("成功创建实例: " + instance);
} catch (ClassNotFoundException e) {
System.out.println("类未找到(预期的): " + e.getMessage());
System.out.println("这是因为DemoClass类可能不存在");
} catch (InstantiationException | IllegalAccessException e) {
System.out.println("实例化失败: " + e.getMessage());
}
// 被动加载一个类
System.out.println("\n被动加载SubClass类:");
System.out.println("SuperClass.staticValue = " + SuperClass.staticValue);
System.out.println("注意:此时SubClass类可能尚未被初始化,因为我们只访问了SuperClass的静态字段");
}
/**
* 演示类加载的触发时机
*/
private static void demonstrateClassLoadingTriggers() {
System.out.println("\n=== 演示类加载的触发时机 ===");
System.out.println("类加载的主动引用(会触发类的初始化):");
System.out.println("1. 使用new关键字创建类的实例");
System.out.println("2. 访问类的静态变量(除了final常量)");
System.out.println("3. 调用类的静态方法");
System.out.println("4. 使用反射API(如Class.forName())");
System.out.println("5. 初始化一个类的子类");
System.out.println("6. 启动类(Java程序入口)");
System.out.println("\n类加载的被动引用(不会触发类的初始化):");
System.out.println("1. 访问类的静态常量(final修饰且在编译期确定值的常量)");
System.out.println("2. 通过数组定义引用类,不会触发类的初始化");
System.out.println("3. 引用类的静态字段,只会触发声明字段的类的初始化");
// 演示通过数组定义引用类
System.out.println("\n演示通过数组定义引用类:");
ArrayClass[] arrays = new ArrayClass[10]; // 不会触发ArrayClass的初始化
System.out.println("创建ArrayClass数组不会触发ArrayClass类的初始化");
// 演示访问静态常量
System.out.println("\n演示访问静态常量:");
System.out.println("ConstantClass.CONSTANT = " + ConstantClass.CONSTANT);
System.out.println("访问编译期常量不会触发ConstantClass类的初始化");
// 演示子类触发父类初始化
System.out.println("\n演示子类触发父类初始化:");
System.out.println("初始化SubClass类会先初始化SuperClass类:");
SubClass.staticMethod(); // 会先初始化SuperClass,再初始化SubClass
}
/**
* 演示类加载的各个阶段
*/
private static void demonstrateClassLoadingStages() {
System.out.println("\n=== 演示类加载的各个阶段 ===");
System.out.println("1. 加载(Loading)阶段:");
System.out.println(" - 通过类的全限定名获取类的二进制字节流");
System.out.println("\n 静态存储结构(编译后的.class文件):");
System.out.println(" +--------------------------------+");
System.out.println(" | 魔数(0xCAFEBABE) |");
System.out.println(" | 版本号(Major.Minor Version) |");
System.out.println(" | 常量池(Constant Pool) |");
System.out.println(" | 访问标志(Access Flags) |");
System.out.println(" | 类索引(This Class) |");
System.out.println(" | 父类索引(Super Class) |");
System.out.println(" | 接口表(Interfaces) |");
System.out.println(" | 字段表(Fields) |");
System.out.println(" | 方法表(Methods) |");
System.out.println(" | 属性表(Attributes) |");
System.out.println(" +--------------------------------+");
System.out.println("\n 代码示例(静态结构):");
System.out.println(" public class Example {");
System.out.println(" private int field; // 字段表");
System.out.println(" public void method() {} // 方法表");
System.out.println(" static final int CONST = 1; // 常量池");
System.out.println(" }");
System.out.println("\n 运行时数据结构(方法区):");
System.out.println(" +--------------------------------+");
System.out.println(" | 类型信息: |");
System.out.println(" | - 类名、访问修饰符 |");
System.out.println(" | - 父类、接口信息 |");
System.out.println(" | 运行时常量池: |");
System.out.println(" | - 字面量 |");
System.out.println(" | - 符号引用 -> 直接引用 |");