在Java中类的加载过程是Java虚拟机将类的字节码加载到内存中、进行验证、然后解析和初始化的过程。在这个过程中涉及多个步骤和执行阶段。Java的类加载机制是动态的,即类在运行时才会被加载。这种机制为Java的高灵活性和跨平台特性提供了支持。下面我们就来详细的介绍一下相关的内容。
Java提供了三种主要的类加载器来动态加载类,如下所示。
Java的类加载器遵循双亲委托机制,即当一个类加载器尝试加载类时,它首先将请求委托给父类加载器,如果父类加载器无法加载该类,才由当前类加载器进行加载。
类的加载生命周期主要包括以下五个阶段
加载(Loading)
类的字节码文件(.class文件)通过类加载器从文件系统、网络或者其他来源加载到内存中。在此过程中,JVM会为每一个加载的类在方法区(Method Area)中生成一个Class对象,它封装了该类的信息,例如类的名称、父类、实现的接口、字段、方法等。
链接(Linking)
链接过程由三个小步骤组成
初始化(Initialization)
初始化阶段是执行类构造器方法的过程。类构造器是由编译器自动生成的,用于初始化类的静态变量和执行静态代码块。如果类存在静态字段,或者有静态代码块,它们会在此阶段执行,并对字段赋初始值。初始化方法只执行一次,是线程安全的。
使用(Using)
当类被加载并初始化后,它的实例可以被创建,类的静态方法可以被调用,静态字段可以被访问。
卸载(Unloading)
类的卸载是由垃圾回收器负责的。当某个类的Class对象不再被引用时,并且这个类的所有实例都被回收,JVM会在适当的时候卸载这个类。类的卸载是无法强制触发的,通常由JVM自动进行。
Java的类加载器使用了父委托机制,即当一个类加载器收到类加载请求时,它会首先将该请求委托给父加载器处理。父类加载器处理的顺序是从最顶层的Bootstrap ClassLoader开始,依次向下。只有当父类加载器无法找到类时,才会由当前类加载器进行加载。
双亲委托机制的优势
虽然Java类加载器遵循父委托模型,但在一些情况下,开发者可能会打破这种机制,通常通过创建自定义类加载器,继承自ClassLoader类并覆盖loadClass()方法。这种做法在一些框架,例如OSGi、Tomcat等中比较常见,它们通过定制类加载器来隔离不同的类加载上下文。
类的加载有两种类型,如下所示。
主动引用
主动引用会导致类的加载和初始化,包括以下情况:
被动引用
某些情况不会触发类的初始化,即不会调用初始化方法方法:
Java的类加载过程是一个复杂而关键的过程,包含了加载、链接、初始化等多个阶段,并依赖于类加载器及其父委托模型来确保类的唯一性和安全性。理解类加载机制有助于开发者在处理类加载异常、ClassNotFoundException、NoClassDefFoundError等问题时更好地进行调试和解决问题。