虚拟机类加载机制及原理

虚拟机的类加载机制是指在Java虚拟机启动的时候,通过类加载器将.class文件加载到内存中,并在内存中生成一个对应的Class对象,Java虚拟机在运行时会根据这个Class对象来执行对应的程序。

Java虚拟机的类加载机制是基于委派机制实现的。当Java虚拟机需要加载一个类时,它首先会委派给其内置的类加载器,如果内置的类加载器无法加载这个类,那么会委派给父类加载器进行加载,如果父类加载器还是无法加载,则会一直往上委派,直到委派给顶层的启动类加载器进行加载。

示例:

假设有一个名为MyObject的Java类,它的定义保存在MyObject.java文件中,MyObject类的代码如下:

public class MyObject {
    public MyObject() {
        System.out.println("MyObject Constructor");
    }
}

在编译后,会生成对应的MyObject.class文件,此时我们尝试使用Java命令来运行这个类:

java MyObject

在运行的过程中,Java虚拟机会通过类加载器将MyObject.class文件加载到内存中,并生成对应的Class对象,然后在内存中执行对应的程序。

Java虚拟机类加载机制的优点是可以在运行时动态加载类,这样就可以在应用程序运行过程中根据需要加载类,从而实现更灵活、更高效的程序设计。同时,由于Java虚拟机的类加载机制是基于委派机制实现的,因此可以实现类隔离、安全沙箱等功能。

虚拟机类加载机制的原理
当Java程序启动时,Java虚拟机就开始工作了。其中一个主要任务就是加载、链接和初始化各个类,使得Java程序可以正确地执行。

Java虚拟机的类加载机制主要分为三个阶段:加载、链接和初始化。

加载
类加载是虚拟机进行的一个过程,它将类的.class文件加载到内存中,并对数据进行校验、准备和解析。

链接
类加载完成后,虚拟机会对类进行链接。链接分为三个阶段:

验证:确保.class文件符合Java虚拟机规范,并且不包含不安全的代码。
准备:为类的静态变量分配内存,并设置默认初始值。
解析:将符号引用转换为直接引用。
初始化
初始化是类加载机制的最后一个阶段,它主要是执行类的静态初始化代码块和静态变量赋值操作,以及调用静态方法。
这三个阶段的过程中,如果出现了错误或异常,虚拟机会抛出ClassNotFoundException、NoClassDefFoundError、LinkageError等异常。

下面是一个简单的示例代码,可以更好地理解类加载机制的原理:

public class MyClass {
    public static void main(String[] args) {
        MyObject obj = new MyObject();
        obj.sayHello();
    }
}

class MyObject {
    public void sayHello() {
        System.out.println("Hello, World!");
    }
}

在执行MyClass的main方法之前,Java虚拟机需要先加载MyClass类和MyObject类。加载的过程中,虚拟机会读取MyClass.class和MyObject.class文件,并将这些类的字节码加载到内存中。之后,虚拟机会对MyClass和MyObject类进行链接和初始化。在初始化MyClass类时,虚拟机会执行main方法。在main方法中,创建了一个MyObject对象,并调用了它的sayHello方法。如果MyObject类没有被正确地加载、链接和初始化,就无法创建这个对象并调用方法,程序就会抛出异常。

当一个 Java 程序被运行时,虚拟机类加载机制的流程如下图所示:

                 +-------------+
                 |  加载阶段   |
                 +-------------+
                        |
          +-------------+-------------+
          |             |             |
  +-------------+  +-------------+ +-------------+
  |  验证阶段   |  | 准备阶段   | | 解析阶段   |
  +-------------+  +-------------+ +-------------+
          |             |             |
          |             |             |
          v             v             v
  +-------------+  +-------------+ +-------------+
  |  初始化阶段 |  | 使用阶段   | | 卸载阶段   |
  +-------------+  +-------------+ +-------------+

1、加载阶段
在加载阶段,虚拟机需要完成以下几个任务:

通过类的全限定名获取类的二进制字节流;
将字节流转化为 JVM 内部的数据结构,即类模板对象;
在内存中生成一个代表该类的 java.lang.Class 对象,作为该类的访问入口。

2、验证阶段
在验证阶段,虚拟机会对类的字节流进行合法性检查,以确保加载的字节流能够被正确解析并执行。主要有以下验证:

文件格式验证
元数据验证
字节码验证
符号引用验证

3、准备阶段
在准备阶段,虚拟机会为类的静态变量分配内存并设置默认的初始值。这里的静态变量并不是指常量,常量是在常量池中准备的。

4、解析阶段
在解析阶段,虚拟机会将类中的符号引用转化为直接引用,以便于后面的访问。解析阶段可以被看作是虚拟机将常量池中的符号引用替换为直接引用的过程。

5、初始化阶段
在初始化阶段,虚拟机会对类进行初始化。在初始化阶段,虚拟机需要完成以下几个任务:

执行类构造器()方法的内容;
如果该类有父类,并且父类还未被初始化,则需要先初始化父类。

6、使用阶段
在使用阶段,虚拟机会执行类中的代码。

7、卸载阶段
在卸载阶段,虚拟机会将已经加载的类从内存中卸载。虚拟机需要完成以下几个任务:

执行类构造器()方法的内容;
如果该类有父类,并且父类还未被初始化,则需要先初始化父类。