java类如何加载
Java 类的加载机制
Java 类的加载是 Java 虚拟机(JVM)将类的字节码文件(.class)加载到内存中,并转换为运行时数据结构的过程。类的加载由类加载器(ClassLoader)完成,遵循双亲委派模型。
类加载的步骤
加载(Loading) 查找并加载类的二进制数据(.class 文件),生成一个代表该类的 Class 对象。类加载器可以从文件系统、网络或其他来源加载类。
验证(Verification) 确保加载的类符合 JVM 规范,防止恶意代码破坏 JVM。验证内容包括文件格式、元数据、字节码和符号引用等。
准备(Preparation)
为类的静态变量分配内存并设置默认初始值(零值)。例如,static int a 的默认值为 0,而非代码中显式赋予的值。
解析(Resolution) 将符号引用转换为直接引用。符号引用是类、方法或字段的名称,直接引用是具体的内存地址或偏移量。

初始化(Initialization)
执行类的静态代码块(static {})和静态变量的显式赋值。这是类加载的最后一步,确保类完全准备好使用。
类加载器层次结构
Bootstrap ClassLoader
加载 Java 核心类库(如 java.lang.*),由 JVM 实现,通常用本地代码编写,不继承 java.lang.ClassLoader。
Extension ClassLoader
加载扩展库(JAVA_HOME/lib/ext 目录下的类),是 sun.misc.Launcher$ExtClassLoader 的实例。

Application ClassLoader
加载应用程序类路径(ClassPath)下的类,是 sun.misc.Launcher$AppClassLoader 的实例。
自定义 ClassLoader
用户可以通过继承 ClassLoader 类实现自定义类加载器,用于特定场景(如热部署、模块化加载)。
双亲委派模型
类加载器在加载类时,先委托父类加载器尝试加载。只有父类加载器无法加载时,子类加载器才会尝试加载。这种机制保证了类的唯一性和安全性,避免重复加载和核心类被篡改。
代码示例:自定义类加载器
public class CustomClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = loadClassData(name); // 从自定义路径加载字节码
if (classData == null) {
throw new ClassNotFoundException();
}
return defineClass(name, classData, 0, classData.length);
}
private byte[] loadClassData(String className) {
// 实现从文件或网络加载字节码的逻辑
return null;
}
}
类加载的触发条件
以下情况会触发类的初始化:
- 创建类的实例(
new关键字)。 - 访问类的静态变量或静态方法。
- 使用反射(
Class.forName())。 - 初始化子类时,父类会先初始化。
- JVM 启动时指定的主类(包含
main方法的类)。
注意事项
- 类加载是懒加载的,只有在首次使用时才会初始化。
- 静态变量的赋值和静态代码块的执行顺序与代码中的声明顺序一致。
- 打破双亲委派模型需谨慎,可能导致类冲突或安全问题。






