Java 中类什么时候加载

在 Java 中,类的加载是指将类的字节码文件加载到内存,并在内存中创建对应的 Class 对象的过程。类的加载是 Java 程序运行的必要环节,只有在类加载完成后,程序才能正常执行和访问类的成员。

类加载的时机

Java 中类的加载时机可以分为以下几种情况:

  1. 当创建类的实例时:当我们使用 new 关键字创建一个类的实例时,JVM 会首先检查该类是否已经加载,如果没有加载,则会触发类的加载过程。

    示例代码如下所示:

    public class MyClass {
        // 类的成员和方法
    }
    
    public class Main {
        public static void main(String[] args) {
            MyClass obj = new MyClass(); // 创建 MyClass 的实例
        }
    }
    
  2. 当访问类的静态成员时:当我们访问一个类的静态成员(包括静态变量和静态方法)时,JVM 会首先检查该类是否已经加载,如果没有加载,则会触发类的加载过程。

    示例代码如下所示:

    public class MyClass {
        public static int myStaticField = 10; // 静态变量
    
        public static void myStaticMethod() { // 静态方法
            System.out.println("Hello, World!");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            System.out.println(MyClass.myStaticField); // 访问静态变量
            MyClass.myStaticMethod(); // 调用静态方法
        }
    }
    
  3. 当使用反射访问类时:当我们使用 Java 的反射机制来访问一个类时,JVM 会首先检查该类是否已经加载,如果没有加载,则会触发类的加载过程。

    示例代码如下所示:

    public class MyClass {
        // 类的成员和方法
    }
    
    public class Main {
        public static void main(String[] args) throws Exception {
            Class<?> clazz = Class.forName("MyClass"); // 通过类名获取 Class 对象
            System.out.println(clazz);
        }
    }
    
  4. 当执行类的主方法时:当我们执行一个 Java 程序时,JVM 会首先加载包含 public static void main(String[] args) 方法的类,然后再执行该方法。

    示例代码如下所示:

    public class Main {
        public static void main(String[] args) {
            System.out.println("Hello, World!");
        }
    }
    

类加载的过程

当一个类被加载时,JVM 会按照以下步骤进行类的加载过程:

  1. 加载(Loading):将类的字节码文件加载到内存中。
  2. 链接(Linking):将字节码文件中的符号引用转换为直接引用,并进行验证、准备和解析等操作。
    • 验证(Verification):确保字节码文件的正确性和安全性。
    • 准备(Preparation):为类的静态变量分配内存,并设置默认初始值。
    • 解析(Resolution):将符号引用转换为直接引用,如将方法的符号引用转换为内存地址。
  3. 初始化(Initialization):对类的静态变量进行显式初始化和静态代码块的执行。

类加载器

在 Java 中,类加载器(ClassLoader)负责将类的字节码文件加载到内存中。JVM 内置了三个主要的类加载器,分别是:

  • 引导类加载器(Bootstrap ClassLoader):负责加载 Java 的核心类,如 java.lang.Object 等,它是 JVM 内置的,没有对应的 Java 类。
  • 扩展类加载器(Extension ClassLoader):负责加载扩展类路径(ext 目录)下的类。
  • 应用程序类加载器(Application ClassLoader):负责加载应用程序类路径(classpath)下的类。

我们也可以通过自定义类加载器来实现类的加载,以满足特定的需求,如实现热部署等。