当前位置: 首页 > article >正文

高级java每日一道面试题-2024年10月26日-JVM篇-JVM的类加载机制是什么?

如果有遗漏,评论区告诉我进行补充

面试官: JVM的类加载机制是什么?

我回答:

JVM(Java虚拟机)的类加载机制是指将Java类的字节码文件(即.class文件)所包含的数据读入内存,并生成数据的访问入口的一种特殊机制。这个机制确保了Java程序能够在运行时动态地加载、链接和初始化类。以下是JVM类加载机制的详细解释:

一、类加载的过程

JVM中类的加载过程分为五个主要阶段:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)和初始化(Initialization)。

1. 加载(Loading)
  • 概述:加载阶段是类加载过程的第一个阶段,主要任务是将字节码文件从各种来源(如文件系统、网络、数据库等)加载到内存中,并将其转换为Class对象。
  • 过程
    1. 读取字节码:类加载器通过类的全限定名找到对应的.class文件。
    2. 生成二进制数据:将读取的字节码转换为二进制数据流。
    3. 创建Class对象:将.class文件中的二进制数据读取到内存中,并将其转换为方法区的运行时数据结构。在堆中生成一个代表该类的java.lang.Class对象,作为对方法区中这些数据的访问入口。
2. 验证(Verification)
  • 概述:验证阶段确保加载的类字节码文件符合JVM规范,没有安全问题。
  • 过程
    1. 文件格式验证:验证字节码文件的格式是否正确,例如魔数、版本号等。
    2. 元数据验证:验证类的元数据信息,例如类的继承关系、方法和字段的描述符等。
    3. 字节码验证:验证字节码指令序列的有效性,确保不会破坏虚拟机的运行状态。
    4. 符号引用验证:验证类的符号引用是否可以被解析为直接引用。
3. 准备(Preparation)
  • 概述:准备阶段为类的静态变量分配内存,并设置默认初始值(零值)。
  • 过程
    1. 分配内存:为类的静态变量(类变量,被static修饰的变量)分配内存,并设置其初始值(注意,这里设置的初始值是Java数据类型的默认值,而不是代码中显式赋予的值)。
    2. 设置默认值:将静态变量初始化为默认值,例如int类型的静态变量初始化为0,boolean类型的静态变量初始化为false等。
4. 解析(Resolution)
  • 概述:解析阶段将类的符号引用转换为直接引用。符号引用是以一组符号来描述所引用的目标,而直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。
  • 过程
    1. 类或接口的解析:将类或接口的符号引用解析为直接引用。
    2. 字段解析:将字段的符号引用解析为直接引用。
    3. 类方法解析:将类方法的符号引用解析为直接引用。
    4. 接口方法解析:将接口方法的符号引用解析为直接引用。
5. 初始化(Initialization)
  • 概述:初始化阶段是类加载过程的最后一个阶段,主要任务是执行类的初始化代码,即执行类的静态初始化块和静态变量的赋值操作。
  • 过程
    1. 执行静态初始化块:执行类中的静态初始化块。
    2. 执行静态变量赋值:执行类中的静态变量的赋值操作。
    3. 父类初始化:如果类有父类,先初始化父类。

二、类加载器

JVM预定义了三种类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extensions ClassLoader)和应用程序类加载器(Application ClassLoader)。

  1. 启动类加载器

    • 负责加载$JAVA_HOME/lib目录中的jar包,或者被参数-Xbootclasspath指定的路径。
    • 由C++实现,不是ClassLoader子类。
  2. 扩展类加载器

    • 负责加载$JAVA_HOME/lib/ext目录或java.ext.dirs指定目录下的jar包。
    • 由Java代码实现,是ClassLoader子类,但父类加载器为null。
  3. 应用程序类加载器

    • 负责加载ClassPath路径的jar包,即应用程序jar包。
    • 由Java代码实现,父类加载器为ExtClassLoader。

此外,开发人员还可以自定义类加载器,通过继承ClassLoader类或者URLClassLoader,并重写其findClass(String name)方法来实现。

三、双亲委派机制

  • 概述:双亲委派模型是一种类加载器之间的层次关系模型,确保类的加载具有唯一性和层次性。
  • 过程
    1. 委派请求:当一个类加载器收到类加载请求时,它首先将请求委托给父类加载器。
    2. 递归委派:父类加载器再将请求委托给它的父类加载器,直到最顶层的启动类加载器(Bootstrap ClassLoader)。
    3. 加载类:如果父类加载器无法加载该类(即在它的搜索路径中没有找到该类),则子类加载器才会尝试自己加载该类。
    4. 加载成功:如果类加载成功,返回Class对象。

四、类加载的时机

类加载的时机并不是在程序编译时确定的,而是在程序运行时根据需要动态加载的。以下是一些常见的类加载时机:

  1. 当使用new关键字创建对象时,会触发对应类的加载和初始化。
  2. 当访问或设置一个类的静态字段时,会触发该类的加载和初始化(被final修饰、编译器优化时已经放入常量池的静态字段除外)。
  3. 当调用一个类的静态方法时,会触发该类的加载和初始化。
  4. 当使用java.lang.reflect包的方法对类进行反射调用时,会触发该类的加载和初始化。
  5. 当初始化一个类时,如果其父类还未进行初始化,则会先触发其父类的初始化。

五、类的卸载

在类使用完成之后,如果满足以下条件,类就会被卸载:

  1. 该类所有的实例都已经被回收,即Java堆中不存在该类的任何实例。
  2. 加载该类的ClassLoader已经被回收。
  3. 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。

如果以上三个条件全部满足,JVM就会在方法区垃圾回收的时候对类进行卸载。类的卸载过程实际上是在方法区中清空类信息,标志着Java类的整个生命周期的结束。

总结

综上所述,JVM的类加载机制是一个复杂而精细的过程,它确保了Java程序的动态性、安全性和稳定性。通过理解这个过程,我们可以更好地编写和维护Java应用程序。


http://www.kler.cn/a/375471.html

相关文章:

  • ChatGPT接口测试用例生成的流程
  • 深入理解 Linux wc 命令
  • 在 Go 中利用 ffmpeg 进行视频和音频处理
  • 电脑使用CDR时弹出错误“计算机丢失mfc140u.dll”是什么原因?“计算机丢失mfc140u.dll”要怎么解决?
  • 国家认可的人工智能从业人员证书如何报考?
  • 【C#】try-catch-finally语句的执行顺序,以及在发生异常时的执行顺序
  • 【机器学习】26. 聚类评估方法
  • Ubuntu 系统、Docker配置、Docker的常用软件配置(下)
  • Docker-in-Docker(DinD)
  • 4:arm汇编语言4:bits/byte的介绍(ASCII码)与二进制补位
  • 【数据结构】guard
  • PyMOL中常用的命令列表
  • 代理人工智能如何应对现代威胁的速度和数量
  • 重载与重写的区别
  • wireshark复制数据
  • 极简实现酷炫动效:Flutter隐式动画指南第二篇之一些酷炫的隐式动画效果
  • 高清解压视频素材从哪儿下载?推荐5个高清推文素材资源网站
  • Unity3D Shader实现法线贴图功能详解
  • 【论文阅读】FUNNELRAG:一个从粗到精的逐级检索范式
  • 静态水印+动态水印,开启超强PPT版权保护!
  • 基于Material Design风格开源、免费的WinForms UI控件库
  • DNF 主从服务器的搭建
  • 传输层协议之UDP
  • 调试EKF的MATLAB代码的关键点
  • 智能交通的未来:深度学习如何改变车辆检测游戏规则
  • 抓取和分析JSON数据:使用Python构建数据处理管道