JVM加载机制

1、JVM加载机制

Class类型通常以文件的形式存在(当然,任何二进制流都可以是Class类型的),只有被Java虚拟机装载的Class类型才能在程序中使用。

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

2、加载步骤

加载(Loading)

这是类加载过程的第一个阶段。在这一阶段,JVM通过类的全名(包括包名)找到并加载.class文件。这些.class文件可以来自文件系统、网络或其他来源。

加载完成后,JVM会在内存中为这个类创建一个对应的java.lang.Class对象,这个对象作为该类所有信息的入口点。

链接(Linking)

链接阶段又可以分为验证、准备和解析三个子阶段。

  • 验证(Verification):验证阶段确保被加载的类的正确性和安全性。它会检查类的字节码是否符合JVM规范,以及是否有潜在的安全风险。
  • 准备(Preparation):准备阶段为类的静态变量分配内存,并设置初始值。注意,这里的初始值是Java虚拟机规范所规定的默认值,而不是在代码中显示的初始值。
  • 解析(Resolution):解析阶段是将常量池内的符号引用转换为直接引用的过程。这涉及到对类、接口、字段和方法的符号引用到实际内存地址的映射。

初始化(Initialization)

初始化阶段是类加载过程的最后一步。在这一阶段,JVM执行类的构造器方法()。这个方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块(static{}块)中的语句合并产生的。
如果一个类有父类,那么在初始化这个类之前,会先初始化其父类。这是为了确保父类中的静态变量和静态代码块在子类使用之前已经被正确初始化。

以下是一个简单的Java程序,演示了类加载的过程:

java 复制代码
public class MyClass {
    static int staticVariable = 10;
    static final int FINAL_STATIC_VAR = 20;
 
    static {
        System.out.println("MyClass static block executed");
    }
}
 
public class Loader {
    public static void main(String[] args) throws ClassNotFoundException {
        // 通过这种方式,我们可以触发类的装载和链接
        Class<?> clazz = Class.forName("MyClass");
 
        // 打印装载和链接过程中的一些信息
        System.out.println("Class " + clazz.getName() + " has been loaded");
 
        // 访问类的静态字段,将触发初始化
        System.out.println("Static variable value: " + MyClass.staticVariable);
        System.out.println("Final static variable value: " + MyClass.FINAL_STATIC_VAR);
    }
}

当运行Loader类的main方法时,JVM将会加载MyClass类,这将触发链接和初始化过程。Class.forName("MyClass")这行代码会装载并链接MyClass类,然后初始化它。在初始化过程中,会执行静态初始化块,并为静态变量赋值。

输出将会是:

java 复制代码
MyClass static block executed
Class MyClass has been loaded
Static variable value: 10
Final static variable value: 20

此外,JVM的类加载机制还遵循双亲委派模型。当一个类加载器需要加载一个类时,它首先会把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中。只有当父类加载器无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。这种机制有助于确保Java应用程序的稳定性和安全性。

需要注意的是,类加载的触发时机并不是随意的,而是在读取或设置一个类的静态变量、对类进行反射调用、虚拟机启动时定义了main()方法的那个类先初始化等特定情况下才会发生。

总的来说,JVM的类加载机制是一个复杂而精巧的系统,它确保了Java程序的正确性和安全性,并提供了"一次编写,到处运行"的能力。

对于java 无参、有参构造方法;静态、非静态代码块执行顺序

可参考另一篇文章
https://blog.csdn.net/qiyeliuli/article/details/54867055

相关推荐
~木雨1 分钟前
String 底层原理与常量池全解析:byte []+coder、intern 陷阱、substring 内存泄漏,一篇讲透
java·jvm·内存优化·string·字符串常量池
笔触狂放21 分钟前
第3章 抓取静态网页数据
爬虫·python
海兰21 分钟前
【 Python 量化交易】开篇
开发语言·python·信息可视化·量化交易
pt104333 分钟前
网络自动化Python课程:Netconf与Restconf及Cisco自动化配置实验
网络·python·自动化
slacker-kian1 小时前
[笔记]-什么是相似性搜索?
python·ai·向量·相似性搜索·点积·l2 距离·余弦相似度和距离
阿童木写作1 小时前
跨境电商图片翻译工具,批量翻译视频字幕还免费
python·音视频
cfm_29141 小时前
ThreadLocal 内存泄漏
java·jvm
sukioe1 小时前
城智连响:基于 LangGraph 与四库分层架构的城市公共设施智能报修与派单系统
人工智能·python·ai·架构·langchain
我的xiaodoujiao1 小时前
Django 基础知识详细图文教程 4-Django 视图定义与使用
开发语言·数据库·后端·测试工具·django·sqlite
l1t1 小时前
DeepSeek总结的DuckDB在 CI 中为 release 和 glibc CLI 构建启用 LTO - #24225
开发语言·数据库·ci/cd·duckdb