JVM的类加载机制是将字节码文件(.class)动态加载到内存,并进行验证、准备、解析和初始化的过程,最终生成可被虚拟机直接使用的类对象。:
一、类加载的五大阶段
加载(Loading)
任务:通过类加载器(ClassLoader)获取类的二进制字节流,并在方法区生成对应的运行时数据结构,同时在堆中创建java.lang.Class对象作为访问入口。
加载来源:本地文件系统、网络(如Applet)、ZIP/JAR包、动态代理生成的类等。
关键点:类加载器(如BootstrapClassLoader、AppClassLoader)按需加载类,JVM仅要求字节流符合规范,不限制生成方式(如支持Scala、Kotlin等语言)。
验证(Verification)
目的:确保字节码合法且不会危害JVM安全。
步骤:
文件格式验证:检查魔数(0xCAFEBABE)、版本号等。
语义验证:检查继承关系、方法重载合法性等。
字节码验证:验证操作数栈类型匹配、跳转指令有效性等。
准备(Preparation)
任务:为类变量(静态变量)分配内存并设置默认初始值(如int为0,引用类型为null)。
例外:final static修饰的常量在编译期直接赋值,此阶段直接生效。
解析(Resolution)
任务:将常量池中的符号引用(如类名、方法名)转换为直接引用(内存地址或偏移量)。
对象类型:类/接口、字段、方法等的解析。
初始化(Initialization)
触发条件:首次主动使用类(如new实例、访问静态变量、调用静态方法、反射等)。
执行内容:执行()方法(由编译器自动合并静态变量赋值和静态代码块生成),按代码顺序初始化静态变量。
线程安全:JVM通过加锁确保多线程下()仅执行一次。
二、类加载器与双亲委派模型
类加载器分类
启动类加载器(Bootstrap ClassLoader):C++实现,加载JAVA_HOME/lib核心类库(如rt.jar)。
扩展类加载器(Extension ClassLoader):加载JAVA_HOME/lib/ext或java.ext.dirs指定的类。
应用类加载器(AppClassLoader):加载用户类路径(Classpath)的类。
自定义类加载器:用户继承ClassLoader实现,用于动态加载非标准路径的类(如网络、数据库)。
双亲委派机制
流程:子加载器收到加载请求时,先委派父加载器处理,仅当父加载器无法完成时,子加载器才尝试加载。
优点:
安全性:防止核心类被篡改(如自定义java.lang.String无效)。
避免重复加载:确保类全局唯一性。
三、类加载的触发场景
以下情况会触发类的初始化(主动使用):
创建类的实例(new)。
访问类的静态变量或方法(非final常量)。
反射调用(如Class.forName())。
初始化子类时,若父类未初始化,则触发父类初始化。
虚拟机启动时指定的主类(包含main()的类)。
四、特殊案例解析
被动引用:访问父类的静态字段不会触发子类初始化,访问编译期常量(final static)不会触发类初始化。
接口初始化:不要求父接口全部初始化,仅在首次使用静态字段时触发。