java面试题-JVM类加载机制

news/2024/4/20 7:56:18/文章来源:https://blog.csdn.net/qq_33129875/article/details/129220101
  1. 类加载的生命周期?

1. 加载阶段(Loading)

在Java程序中,当需要使用某个类时,JVM会使用类加载器来查找并加载该类文件。类加载器会首先从文件系统或网络中查找相应的 .class 文件,读取类的二进制数据,并将其存储在JVM的内存中。在这个过程中,JVM会为该类创建一个对应的Java类对象。这个Java类对象包含了该类的类名、父类名、接口名、访问修饰符、成员变量和成员方法等信息。

2. 链接阶段(Linking)

在类加载完成后,JVM会对该类进行链接。链接分为三个步骤:验证、准备和解析。

  • 验证阶段:在验证阶段,JVM会对类文件的格式、依赖关系、语义等进行检查。如果验证失败,JVM会抛出相应的异常。

  • 准备阶段:在准备阶段,JVM会为类的静态成员分配内存空间,并设置默认初始值。在Java程序中,静态变量的默认初始值是0或null,而不是程序员在代码中定义的初始值。如果类的静态成员是常量,则在编译期间就已经分配了内存空间,并设置了正确的初始值。因此,在准备阶段,常量并不需要分配内存空间。

  • 解析阶段:在解析阶段,JVM会将类中的符号引用转换为直接引用。在Java程序中,类中的方法调用、变量引用等都是通过符号引用实现的。而在JVM中,这些符号引用需要被解析为直接引用,以便JVM能够正确地执行程序。在解析阶段,JVM会将符号引用转换为直接引用,并生成相应的调用指令。

3. 初始化阶段(Initialization)

在初始化阶段,JVM会为类的静态成员赋予正确的值。在Java程序中,静态变量和静态代码块的初始化操作都是在初始化阶段完成的。当JVM完成初始化操作后,Java程序才能正常地使用该类。需要注意的是,初始化操作只会执行一次。如果类已经被初始化过,JVM不会再次执行初始化操作。

总体来说,Java类加载器的生命周期可以分为加载、链接和初始化三个阶段。在这三个阶段中,JVM会对类文件进行验证、解析、分配内存空间、设置初始值等操作,以确保Java程序的正确执行。

2.类加载器的层次?

在Java中,类加载器的层次结构可以分为以下三个层次:

  1. 启动类加载器(Bootstrap ClassLoader)

启动类加载器是JVM内置的类加载器,它负责加载JRE核心库中的类,包括 rt.jarresources.jar 中的类。它是Java类加载器中唯一没有父类加载器的加载器,由JVM自身实现。在Java程序中,我们无法直接获取到启动类加载器的引用。

  1. 扩展类加载器(Extension ClassLoader)

扩展类加载器是用来加载JRE扩展目录中的类,通常位于 jre/lib/ext 目录下。它的父类加载器是启动类加载器。扩展类加载器的实现由JVM提供,它可以通过 java.lang.ClassLoader.getSystemClassLoader().getParent() 获取到其父类加载器。

  1. 应用程序类加载器(Application ClassLoader)

应用程序类加载器(也称为系统类加载器)是用来加载应用程序类路径上的类,通常位于 classpath 下的类和库。它的父类加载器是扩展类加载器。应用程序类加载器的实现也由JVM提供,可以通过 java.lang.ClassLoader.getSystemClassLoader() 获取到其引用。

  1. 自定义类加载器

除了这三个基本的类加载器,Java还支持自定义类加载器。自定义类加载器可以继承自 java.lang.ClassLoader 类,通过重写其中的 findClass() 方法和 loadClass() 方法实现类的加载。这样可以实现特定的类加载需求,比如从网络或数据库中动态加载类。在实现自定义类加载器时,需要注意遵循双亲委派模型的原则,保证类的唯一性和正确性。

3.Class.forName()和ClassLoader.loadClass()区别?

在Java中,Class.forName()ClassLoader.loadClass() 都可以用来加载类,但二者有一些区别。

  1. 类加载器的区别

Class.forName() 方法使用的是当前线程的类加载器(即调用 Class.forName() 方法的类的类加载器)来加载指定的类。如果没有指定类加载器,那么默认使用的是系统类加载器。如果这个类还没有被加载,那么该方法将加载并初始化这个类。如果这个类已经被加载,那么该方法将返回这个类的 Class 对象。此外,Class.forName() 还可以指定是否要初始化这个类。

ClassLoader.loadClass() 方法是一个实例方法,需要通过类加载器的实例来调用。它只是简单地加载指定的类,但不会对其进行初始化操作。如果想对这个类进行初始化,需要调用 Class.forName()Class.newInstance() 方法。

  1. 返回值的不同

Class.forName() 方法返回一个 Class 对象,该对象包含了类的所有信息,包括类的名称、方法、属性等。

ClassLoader.loadClass() 方法只是简单地加载类,返回的是一个 Class<?> 类型的对象,只包含类的类型信息。如果需要使用该类的实例对象,还需要通过反射或者其他方式来获取。

  1. 加载类的方式的不同

Class.forName() 方法会在加载类的同时对其进行初始化操作,这意味着会执行静态代码块和初始化类变量等操作。

ClassLoader.loadClass() 方法只会简单地加载类,不会执行任何初始化操作。如果需要对类进行初始化,需要手动调用 Class.forName() 或者 Class.newInstance() 方法。

需要注意的是,Class.forName()ClassLoader.loadClass() 在加载类时都会遵循双亲委派模型。即当一个类加载器需要加载一个类时,它首先委派给其父类加载器去加载,如果父类加载器无法加载该类,再由该类加载器自己尝试加载。这样可以保证类的唯一性和正确性。

4.JVM有哪些类加载机制?

Java虚拟机(JVM)的类加载机制主要包括以下几种:

  1. 全盘负责机制(Bootstrap ClassLoader)

Java虚拟机内置的启动类加载器(Bootstrap ClassLoader)会负责加载Java平台核心库中的类,包括 java.langjava.util 等类。由于这些类都是由JVM实现的,因此在加载这些类时,不需要考虑类的版本和安全性问题。

  1. 父类委托机制(Parent Delegation Model)

父类委托机制是Java类加载机制中的核心机制。当一个类需要被加载时,它会先委托给父类加载器去尝试加载。如果父类加载器无法加载这个类,那么它才会由当前类加载器自己去加载。这个过程会一直持续到最顶层的启动类加载器为止,如果仍然无法加载该类,那么就会抛出 ClassNotFoundException 异常。

父类委托机制可以保证Java虚拟机中的类不会出现重名的情况,而且可以保证Java类库的安全性。

  1. 缓存机制(Cache Mechanism)

缓存机制是指,在类加载器加载一个类之后,会将这个类的Class对象缓存起来,下次再加载这个类时,就可以直接从缓存中取出,避免重复加载。

缓存机制可以提高类的加载效率,避免重复加载类的字节码,但同时也可能会导致内存泄漏问题。

  1. 双亲委派机制(Double-Delegation Mechanism)

双亲委派机制是一种更加严格的父类委托机制。在双亲委派机制中,除了顶层的启动类加载器,每个类加载器都有且只有一个父类加载器,并且会优先委托给父类加载器去加载类。如果父类加载器无法加载该类,才会尝试自己去加载。这样可以保证类的唯一性和正确性,避免了重复加载和安全问题。

  • 当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。

  • 当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。

  • 如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载;

  • 若ExtClassLoader也加载失败,则会使用AppClassLoader来加载,如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_74363.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

链表(一):移除链表元素、设计链表等力扣经典链表题目

203.移除链表元素相关题目链接&#xff1a;力扣 - 移除链表元素题目重现给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。思路链表的删除操作如上图所示&#xff0c;我们需要先找到要删除的…

物联网的新应用--触摸物联网

摘要&#xff1a;本文介绍一下触摸物联网的新进展--电子皮肤的物联网应用。还以为物联网的作用领域单单是从现场采集数据或者传输命令到执行设备吗&#xff1f;不&#xff0c;物联网的应用范围远比控制一盏灯大的多。据网上报道&#xff0c;香港城市大学&#xff08;城大&#…

响应性基础API

一.什么是proxy和懒代理&#xff1f;什么是proxy?proxy对象是用于定义基本操作的自定义行为(如&#xff1a;属性查找&#xff0c;赋值&#xff0c;枚举&#xff0c;函数调用等等)。什么是懒代理&#xff1f;懒代理&#xff1a;在初始化的时候不会进行全部代理&#xff0c;而是…

简历信息提取论文笔记Information Extraction from Resume Documents in PDF Format

标题&#xff1a;Information Extraction from Resume Documents in PDF Format下载地址&#xff1a;https://library.imaging.org/ei/articles/28/17/art00013长度&#xff1a;8页发表时间&#xff1a;2016引用量cite27先读标题、摘要、结论、然后 methods/experiment design,…

Zebec社区上线ZIP-2(地平线升级行动)提案,海量激励将被释放

此前&#xff0c;Zebec社区在上线了投票治理系统Zebec Node后&#xff0c;曾上线了首个提案ZIP-1&#xff0c;对 Nautilus Chain 的推出进行了投票&#xff0c;作为 Zebec Chain 上线前的“先行链”&#xff0c;该链得到了社区用户的欢迎&#xff0c;投通过票的比例高达98.3%。…

Spring之丐版IOC实现

文章目录IOC控制反转依赖注入Bean的自动装配方式丐版IOC实现BeanDefinition.javaResourceLoader.javaBeanRegister.javaBean和DI的注解BeanFactory.javaApplicationContext测试&#xff0c;实现在这里插入图片描述大家好&#xff0c;我是Leo。Spring核心中依赖注入和IOC容器是非…

Springboot整合 Thymeleaf增删改查一篇就够了

很早之前写过Thymeleaf的文章&#xff0c;所以重新温习一下&#xff0c;非前后端分离&#xff0c;仅仅只是学习 官网&#xff1a; https://www.thymeleaf.org/ SpringBoot可以快速生成Spring应用&#xff0c;简化配置&#xff0c;自动装配&#xff0c;开箱即用。 JavaConfigur…

Python每日一练(20230226)

目录 1. 合并列表中字典字段 ★ 2. 乘积最大子数组 ★★ 3. 加油站 ★★ 附录 贪心算法 一般步骤 使用条件 存在问题 应用实例 1. 合并列表中字典字段 如下两个列表&#xff0c;需要将oldList转化为newList&#xff0c;去掉相同字段的字典&#xff0c;并且去掉的参…

【RockerMQ】002-RockerMQ 基本概念、系统架构

【RockerMQ】002-RockerMQ 基本概念、系统架构 文章目录【RockerMQ】002-RockerMQ 基本概念、系统架构一、基本概念1、消息&#xff08;Message&#xff09;2、主题&#xff08;Topic&#xff09;3、标签&#xff08;Tag&#xff09;4、队列&#xff08;Queue&#xff09;5、消…

MySql触发器学习

文章目录1 触发器1.1介绍1.2 创建触发器1.2 删除触发器1.3查看触发器1 触发器 1.1介绍 触发器是与表有关的数据库对象&#xff0c;指在 insert/update/delete 之前或之后&#xff0c;触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的…

解决前端组件下拉框选择功能失效问题

问题&#xff1a; 页面下拉框选择功能失效 现象&#xff1a; 在下拉框有默认值的情况下&#xff0c;点击下拉框的其他值&#xff0c;发现并没有切换到其他值 但是在下拉框没默认值的情况下&#xff0c;功能就正常 原因 select 已经绑定选项&#xff08;有默认值&#xff09; 在…

Java异常架构与异常关键字

Java异常简介 Java异常是Java提供的一种识别及响应错误的一致性机制。 Java异常机制可以使程序中异常处理代码和正常业务代码分离&#xff0c;保证程序代码更加优雅&#xff0c;并提高程序健壮性。在有效使用异常的情况下&#xff0c;异常能清晰的回答what, where, why这3个问…

keepalive + nginx 来实现 对于nginx的高可用, 以及如何搭建主备模式

keepalive nginx 来实现 对于nginx的高可用, 以及如何搭建主备模式。 keeplived简介 Keepalived是用纯ANSI/ISO C编写的。该软件围绕一个中央I/O多路复用器进行连接&#xff0c;以提供实时网络设计。 1.1 Keepalived进程被分为3个不同进程 A.一个极简的父进程&#xff0c…

【JavaSE】复习(进阶)

文章目录1.final关键字2.常量3.抽象类3.1概括3.2 抽象方法4. 接口4.1 接口在开发中的作用4.2类型和类型之间的关系4.3抽象类和接口的区别5.包机制和import5.1 包机制5.2 import6.访问控制权限7.Object7.1 toString()7.2 equals()7.3 String类重写了toString和equals8.内部类8.1…

【深度学习】什么是线性回归逻辑回归单层神经元的缺陷

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录逻辑回归&线性回归单层神经元的缺陷单层神经元的缺陷逻辑回归&线性回归 线性回归预测的是一个连续值&#xff0c; 逻辑回归给出的”是”和“否”的回答. 等…

4、算法MATLAB---认识矩阵

认识矩阵1、矩阵定义和基本运算1.1 赋值运算符&#xff1a;1.2 等号运算符&#xff1a;1.3 空矩阵1.4 一行一列矩阵1.5 行矩阵&#xff08;元素用空格或逗号分隔&#xff09;1.6 列矩阵&#xff08;分号表示换行&#xff09;1.7 m行n列的矩阵&#xff1a;行值用逗号间隔&#x…

如何在Linux中实现进程间通信

致前行路上的人&#xff1a; 要努力&#xff0c;但不要着急&#xff0c;繁花锦簇&#xff0c;硕果累累都需要过程&#xff01; 目录 1.进程间通信介绍 1.1进程间通信的目的 1.2进程间通信发展 1.3进程间通信分类 1.4进程间通信的本质 2.管道 2.1什么是管道 2.2管道与进程的关系…

轻量级网络模型ShuffleNet V2

在学习ShuffleNet V2内容前需要简单了解卷积神经网络和MobileNet,以及Shuffnet V1的相关内容&#xff0c;大家可以出门左转&#xff0c;去看我之前的几篇博客MobileNet发展脉络&#xff08;V1-V2-V3&#xff09;&#xff0c;轻量级网络模型ShuffleNet V1&#x1f197;&#xff…

Android 高工分享一波性能优化的总结~

随着 Android 开发越来越规范&#xff0c;国内工程师的素质&#xff0c;以及用户对产品的要求也越来越高。这也间接导致我们对研发项目的质量要求到了近乎苛刻的地步&#xff0c;**内存优化、UI 卡顿优化、App 崩溃监控等性能调优也逐渐成了人手必备的技能。**工作之余&#xf…

【数据挖掘】1、综述:背景、数据的特征、数据挖掘的六大应用方向、有趣的案例

目录一、背景1.1 学习资料1.2 数据的特征1.3 数据挖掘的应用案例1.4 获取数据集1.5 数据挖掘的定义二、分类三、聚类四、关联分析五、回归六、可视化七、数据预处理八、有趣的案例8.1 隐私保护8.2 云计算的弹性资源8.3 并行计算九、总结一、背景 1.1 学习资料 推荐书籍如下&a…