解析Java类加载的运行机制和双亲委派模型

类加载运行机制

类加载形如把.class文件,加载到内存中,得到类对象这样的过程

类加载一共分为五个步骤:

  1. 加载
  2. 验证
  3. 准备
  4. 解析
  5. 初始化

加载

类加载的第一步是将编译好的 Java 类的字节码文件加载到 Java 虚拟机(JVM)中。类加载器会根据类的名称找到对应的字节码文件,并将其读取到内存中。

验证

在验证阶段,虚拟机会对加载的字节码文件进行合法性验证,包括文件格式的验证、验证字节码的正确性和安全性等。这一步主要用于确保 class 文件不会引起虚拟机的错误或安全问题。

准备

在准备阶段,虚拟机会为加载的类分配内存空间,并设置类的默认初始值。这些初始值包括零值(0、false或null)或者用户所设置的初始值。

解析

解析阶段是将常量池中的符号引用转换成直接引用的过程。符号引用包括类、接口、字段和方法等的引用。解析操作的主要目的是为了创建对应的直接引用,以便于后续的内存空间分配、类的初始化和方法的调用等操作。

在 Java 语言中,当我们在代码中引用一个类、接口、字段或方法时,实际上是通过符号引用来表示的。符号引用是一种符号化的描述方式,它并不指向具体的内存地址或偏移量,而是通过符号的形式来描述所引用的目标。

举个例子,假设有以下代码片段:


public class ClassA {
    
    
    public void methodA() {
    
    
        ClassB b = new ClassB();
        b.methodB();
    }
}

public class ClassB {
    
    
    public void methodB() {
    
    
        System.out.println("Method B is called");
    }
}

ClassAmethodA方法中,我们创建了一个ClassB的实例,并调用了它的methodB方法。

在解析阶段,虚拟机会进行如下的符号引用转换为直接引用的过程:

  1. 虚拟机会解析ClassAClassB的符号引用,找到对应的类ClassB的描述符和其他信息。
  2. 虚拟机会在内存中为ClassB分配空间,创建ClassB的实例对象。
  3. 虚拟机会将b变量与实际的内存地址关联起来,这样可以通过b来访问ClassB对象。
  4. 虚拟机会通过b.methodB()来调用ClassBmethodB方法,这里的methodB是一个直接引用。

所以,在解析阶段,虚拟机将符号引用转换为直接引用,这样就能够通过直接引用来访问和使用目标类的字段或方法。通过这种方式,虚拟机可以动态地解析和链接类之间的关系,实现类的动态绑定和调用。

初识化

在初始化阶段,虚拟机会执行类的初始化代码,例如静态变量的赋值和静态代码块的执行等。
这一阶段的触发条件包括:

  1. 类的实例被创建;
  2. 类的静态方法被调用;
  3. 类中的静态字段被赋值。

类的初始化是类加载的最后一个步骤。

双亲委派模型

双亲委派模型(又称为双亲委派机制)是Java类加载机制中的一种设计思想和实现方式
类加载机制是Java虚拟机(JVM)加载类的过程,而双亲委派模型是指在类加载过程中,JVM通过委派的方式来从不同的类加载器去加载类。这个机制主要用于确保类的一致性、安全性和避免重复加载。

在JVM中,有三个类加载器:

  • BootStrap ClassLoader 负责加载java标志库中的类
  • Extension ClassLoader 负责加载一些非标准的但是是Sun/Oracle 扩展的库的类
  • Application ClassLpader 负责加载项目中自己写的类以及第三方库中的一些类

在这里插入图片描述
一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

双亲委派模型基于以下几个原则:

  1. 父类加载器优先:如果一个类需要被加载,JVM首先会把这个任务委派给父类加载器来完成。
  2. 双亲委派:父类加载器在接收到加载请求后,会先检查自己是否已经加载了这个类。如果已经加载,则直接返回该类的Class对象。如果没有加载,则将加载请求向上委派给父类的父类加载器,以此类推,直到顶层的启动类加载器。只有当父类加载器不能完成加载任务时,子加载器才会尝试自己去加载
    3.** 缓存机制:如果一个类被某个加载器加载成功后,这个加载器会将加载结果缓存起来,下次再加载同样的类时直接返回缓存的结果**。

通过双亲委派模型,可以有效地避免类的重复加载和类的不一致性问题。

猜你喜欢

转载自blog.csdn.net/st200112266/article/details/131702973