text: JVM虚拟机类加载机制
  Java 中的类加载机制是指在程序运行时，将编写好的 Java 代码文件（.java）编译成字节码文件（.class），并将字节码文件加载到 JVM 中进行解析、验证、初始化和使用的过程。
  类加载机制主要包括以下三个步骤：
  1. 加载（Loading）：当程序需要使用一个类时，JVM 会通过类的全名找到对应的 .class 文件，并将其加载到内存中。类的加载可以通过系统自带的类加载器或者自定义的类加载器来完成。
  2. 验证（Verification）：在加载完类之后，JVM 会对该类进行验证，以确保该类符合 Java 虚拟机规范及安全性要求。具体包括文件格式验证、元数据验证、字节码验证和符号引用验证等。
  3. 准备（Preparation）：在验证通过之后，JVM 会为该类分配内存空间，并初始化类变量和静态变量的默认值。
  4. 解析（Resolution）：在准备阶段之后，JVM 会将该类中的符号引用转换为直接引用，以方便程序调用。
  5. 初始化（Initialization）：在准备阶段之后，JVM 会执行类的构造器（<clinit> 方法），对静态变量和静态代码块进行初始化操作。如果该类存在父类，则会先对父类进行初始化。
  以上五个步骤组成了类加载机制的完整过程，确保了程序能够正确地使用所需要的类和资源。
  类加载器（Class Loader）是Java虚拟机（JVM）的一个子系统，负责将Java类文件加载到内存中并转换为运行时数据结构，以便程序在运行时能够访问这些类。在Java应用程序中，每个类都由其自己的类加载器加载。类加载器有三种类型：
  1. Bootstrap ClassLoader：也称为引导类加载器，它是最顶层的类加载器，它负责加载JRE核心库中的类，如java.lang包中的类等。
  2. Extension ClassLoader：也称为扩展类加载器，它负责加载Java平台扩展库中的类，位于jre/lib/ext目录下。
  3. Application ClassLoader：也称为系统类加载器，它负责加载应用程序classpath下的类。
  除了这三种标准类加载器之外，还可以通过编写自定义类加载器来实现特定功能的需求，比如动态加载class文件、从网络加载class文件等。
  类装载的执行过程一般分为以下三个步骤：
  1. 加载（Loading）：类加载器通过类的全限定名（例如java.lang.Object）找到对应的二进制字节码文件，并读取到JVM内部。通常情况下，这个二进制字节码文件是由编译器从Java源文件生成的。
  2. 链接（Linking）：在链接阶段，会进行以下三个步骤：
  a.验证（Verification）：确保该类的字节码符合JVM规范，并且不包含不安全或危险的代码。
  b.准备（Preparation）：为类的静态变量分配内存并设置默认初始值。注意，这里不包括实例变量。
  c.解析（Resolution）：将符号引用转换为直接引用，以便在之后的执行过程中能够直接访问其所指向的对象或方法。
  3. 初始化（Initialization）：初始化阶段是类加载的最后一个阶段，在此阶段，JVM执行类构造器<clinit>()方法。该方法是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的。这个方法主要完成类的初始化工作，比如对静态变量赋初值、执行静态代码块等。
  需要注意的是，类的初始化是一个线程安全的过程，并且只会进行一次。如果一个类已经被初始化过了，那么重复初始化也不会再执行<clinit>()方法。
  双亲委派模型是一种Java类加载器的层次结构，也是一种类加载机制。它是指当一个类加载器要加载一个类时，它会先把这个请求委派给它的父类加载器去完成，因此如果父类加载器能够完成类的加载，就不需要子类加载器再加载一遍，反之则由子类加载器自行完成。
  在双亲委派模型中，类加载器按照一定的顺序从上到下依次加载类，具体过程如下：
  1. 首先，当一个类加载器收到类加载请求时，它会先查看自己是否已经加载了该类。如果已经加载，则直接返回该类的Class对象；否则，进入步骤2。
  2. 接下来，该类加载器会把加载请求委托给其父类加载器，让父类加载器去尝试加载该类。如果父类加载器可以成功加载该类，则直接返回该类的Class对象；否则，进入步骤3。
  3. 最后，如果父类加载器还没有成功加载该类，则该类加载器会自己尝试加载该类。如果它能够成功加载该类，则直接返回该类的Class对象；否则，抛出ClassNotFoundException异常。
  实际上，Java中存在三种类加载器：Bootstrap ClassLoader、Extension ClassLoader和System ClassLoader。其中，Bootstrap ClassLoader是虚拟机内置的类加载器，用于加载Java核心库中的类；Extension ClassLoader用于加载Java扩展库中的类；而System ClassLoader则用于加载应用程序自己编写的类。在双亲委派模型中，这三种类加载器形成了一棵树形结构，其中Bootstrap ClassLoader位于最顶层，Extension ClassLoader和System ClassLoader位于其下方。这种层次结构可以保证JVM中的所有类都能被正确地加载并执行，同时也能够防止用户自定义的类覆盖JDK中的重要类。
  动态类加载指的是在程序运行时，通过自定义的类加载器动态地将Java类文件加载到JVM内存中。相比于静态类加载，在编译期就将所有的Java类文件打包成Jar包或War包并部署，动态类加载更加灵活和自由，能够根据实际情况动态地加载和卸载类。
  动态类加载一般分为以下几个步骤：
  1. 自定义类加载器：首先需要编写一个自定义的类加载器，通常继承自ClassLoader类，并重载findClass()方法。在这个方法中可以实现从本地磁盘、网络、数据库等其他数据源中读取class文件并转化为字节数组，然后调用defineClass()方法将字节数组转化成Class对象；
  2. 加载字节码：在自定的类加载器中，通过读取字节码文件所在的地址，将class文件读入内存，并转换为二进制流；
  3. 转换为类对象：使用定义在ClassLoader类中的defineClass()方法，将二进制流转换为Java类对象；
  4. 实例化对象：在获取类对象的情况下，使用newInstance()方法实例化该对象。
  动态类加载在很多场景下都有广泛应用，例如插件化开发、热部署、动态代理等等。需要注意的是，在使用动态类加载时，要防止类加载器的内存泄漏问题，及时卸载不再需要的类。
  在Java虚拟机中，当一个类不再被任何对象引用时，就可以被垃圾回收器进行回收。具体来说，当满足以下条件时，JVM才会对一个类进行回收：
  1. 该类的所有实例都已经被GC回收：在Java虚拟机中，每个类实例都是一个对象，因此当该类的所有实例都已经被GC回收时，该类也就不再有实际意义了。
  2. 该类的ClassLoader已经被GC回收：在Java虚拟机中，每个类都是由其所属的ClassLoader加载的，因此当该类的ClassLoader已经被GC回收时，该类也就没有存在的必要了。
  3. 所有该类的实例都已经被显式地设置为null：如果某个类的实例被显式地设置为null，则说明该实例不再需要，因此类也就不需要存在了。
  需要注意的是，JVM对于类的回收比较谨慎，即使某个类满足上述条件，也不一定能够立刻被回收。因为类的卸载涉及到整个应用程序的安全性和稳定性，需要进行一系列复杂的处理，确保卸载操作不会影响到其他正在运行的代码。因此，在实际开发中，很难直接观察到类的回收过程，但可以通过一些工具（如JConsole、VisualVM等）来监控和分析内存使用情况。