一个类的完整生成过程包括加载、连接和初始化三个阶段。
-
加载:类加载是指通过类加载器将类的字节码文件加载到内存中。加载阶段包括以下几个步骤:
- 加载:查找并加载类的字节码文件。
- 验证:验证字节码的正确性和安全性。
- 准备:为类的静态变量分配内存并进行默认初始化。
- 解析:将符号引用转换为直接引用。
-
连接:连接阶段是对加载后的类进行链接处理,包括以下步骤:
- 验证:再次验证类的结构和语义的正确性。
- 准备:为类的静态变量分配内存并进行初值化。
- 解析:将常量池中的符号引用转换为直接引用。
-
初始化:初始化阶段是真正执行类的初始化代码,给静态变量赋予初始值,并执行静态代码块。初始化阶段是类加载的最后一步。
在java的加载过程中使用的是双亲委派机制(层层调用),先使用最先的bootstrap classloader检查是否可以进行加载,可以,丢给下一个extclassloader进行加载,验证完成通过appclassloader进行加载,任何一个加载器验证失败都将抛出错误
Bootstrap Class Loader(启动类加载器)在加载类的过程中也会进行验证。验证阶段是类加载过程的一个重要步骤,用于确保被加载的字节码文件的正确性和安全性。
在验证阶段,Bootstrap Class Loader会对字节码进行以下验证操作:
- 文件格式验证:验证字节码文件的结构是否符合Java虚拟机规范,包括校验魔数、版本号等。
- 元数据验证:验证字节码文件中的元数据信息是否正确,例如类与超类之间的继承关系是否正确、字段与方法的访问修饰符是否合法等。
- 字节码验证:通过数据流和控制流分析,验证字节码的类型转换是否正确、跳转指令是否有效等,以确保字节码的执行不会导致类型错误或其他异常。
- 符号引用验证:验证类加载过程中的符号引用是否能够正确解析,确保所引用的类、字段、方法存在并可访问。
验证阶段有助于防止恶意类的加载和执行,确保Java虚拟机的安全性和稳定性。
需要注意的是,对于启动类加载器来说,它加载的是位于<JAVA_HOME>/jre/lib
目录下的核心类库,这些类库由Java虚拟机的实现者提供,并经过了严格的测试和验证。因此在实际情况下,验证阶段的操作可能相对较少,因为这些类库已经在开发过程中得到了验证。
总之,Bootstrap Class Loader在加载类的过程中也会进行验证,以确保被加载的字节码文件的正确性和安全性。
Bootstrap Class Loader(启动类加载器)验证通过但无法加载某个类时,它会将加载请求委托给下一个类加载器进行加载。在标准的类加载器层次结构中,下一个类加载器通常是Extension Class Loader(扩展类加载器)。
Extension Class Loader是Java虚拟机内置的一个子类加载器,它负责加载位于<JAVA_HOME>/jre/lib/ext
目录下的扩展类库。该类加载器的父加载器是Bootstrap Class Loader。
当Bootstrap Class Loader无法加载某个类时,它会将加载请求传递给Extension Class Loader。Extension Class Loader首先会尝试从扩展类库中查找并加载该类。如果Extension Class Loader也无法加载该类,它会继续将加载请求传递给下一个加载器,即System Class Loader(系统类加载器)。
System Class Loader是应用程序的默认类加载器,它负责加载应用程序类路径(Classpath)上的类。这包括应用程序的类文件和第三方库等。
如果System Class Loader仍然无法加载该类,它会抛出ClassNotFoundException异常,指示类找不到。这意味着整个类加载器层次结构都无法加载该类。
总结来说,当Bootstrap Class Loader验证通过但无法加载某个类时,它会将加载请求委托给下一个类加载器(如Extension Class Loader),直到找到能够加载该类的类加载器或整个类加载器层次结构都无法加载。这样的委托机制保证了类加载器层次结构的灵活性和可扩展性。
在 Java 类的加载过程中,类在被加载之前会进行一些准备工作。以下是常见的加载前的准备工作:
-
词法分析与语法分析:Java 编译器会对源代码进行词法分析和语法分析,将其转换为抽象语法树(Abstract Syntax Tree,AST)表示。
-
编译为字节码:经过词法和语法分析后,编译器将源代码编译成字节码。字节码是一种中间表现形式,它是可被 Java 虚拟机(JVM)解释执行的格式。
-
验证:类加载器会对字节码进行验证,确保其符合 Java 虚拟机规范。验证过程包括类型检查、符号引用验证、字节码验证等。
-
准备阶段:在准备阶段,类加载器为类变量(静态变量)分配内存,并设置默认值。这些变量将在后续的初始化阶段进行初始化。
-
解析阶段:在解析阶段,类加载器将符号引用转换为直接引用。符号引用是一种编译时的名称,而直接引用是在运行时可以直接使用的内存地址或偏移量。解析阶段包括将类、接口、字段和方法的符号引用解析为直接引用。
当Extension Class Loader(扩展类加载器)无法加载某个类时,加载请求会继续被委托给下一个类加载器,即Application Class Loader(应用程序类加载器,也称为System Class Loader)。
Application Class Loader是Java虚拟机内置的最后一个默认类加载器,它负责加载应用程序类路径上的类,包括应用程序自身的类和第三方库等。
如果Extension Class Loader无法加载某个类,它会将加载请求传递给Application Class Loader。Application Class Loader首先会尝试从应用程序类路径上查找并加载该类。如果Application Class Loader也无法加载该类,它会抛出ClassNotFoundException异常,指示类找不到。
需要注意的是,Application Class Loader是可定制的,可以由开发人员自定义并替换为其他类加载器。因此,在一些特殊的应用场景中,可能存在不同于默认的Application Class Loader的类加载器。
总之,当Extension Class Loader无法加载某个类时,加载请求会继续被委托给Application Class Loader。如果Application Class Loader仍然无法加载该类,它将抛出ClassNotFoundException异常,表示类找不到。
以上是类加载前的主要准备工作。当这些工作完成后,类将进入初始化阶段,进行类变量的真正初始化、静态代码块的执行等操作。
cglib的动态代理过程就在字节码阶段进行了介入
在类加载前准备工作完成后,类将进入初始化阶段
类的初始化包括以下步骤:
-
加载:查找并加载类的字节码文件。类加载器根据类的全限定名来定位字节码文件,并将其加载到内存中。
-
连接(Verification、Preparation、Resolution):
- 验证(Verification):对加载的字节码进行验证,确保其符合 Java 虚拟机规范,包括验证字节码的格式、语义等。
- 准备(Preparation):为类变量(静态变量)分配内存空间,并设置默认初始值。
- 解析(Resolution):将常量池中的符号引用解析为直接引用,以便后续使用。
-
初始化:对类变量进行赋初值和执行静态代码块。在这个阶段,类的构造方法不会被执行。
类的初始化是按需进行的,只有在以下情况下才会触发类的初始化:
- 创建类的实例;
- 访问类的静态变量或调用类的静态方法;
- 使用反射方式访问类。
需要注意的是,如果一个类是另一个类的子类,在初始化子类之前会先初始化父类。