java八股文面试[JVM]——类加载器

news2025/1/19 6:56:33

在这里插入图片描述

 

一、类加载器的概念
类加载器是Java虚拟机用于加载类文件的一种机制。在Java中,每个类都由类加载器加载,并在运行时被创建为一个Class对象。类加载器负责从文件系统、网络或其他来源中加载类的字节码,并将其转换为可执行的Java对象。类加载器还负责解析类的依赖关系,即加载所需的其他类。

Java虚拟机定义了三个主要的类加载器:

启动类加载器(Bootstrap Class Loader):也称为根类加载器,它负责加载Java虚拟机的核心类库,如java.lang.Object等。启动类加载器是虚拟机实现的一部分,它通常是由本地代码实现的,不是Java类。

扩展类加载器(Extension Class Loader):它是用来加载Java扩展类库的类加载器。扩展类库包括javax和java.util等包,它们位于jre/lib/ext目录下。

应用程序类加载器(Application Class Loader):也称为系统类加载器,它负责加载应用程序的类。它会搜索应用程序的类路径(包括用户定义的类路径和系统类路径),并加载类文件。

除了这三个主要的类加载器,Java还支持自定义类加载器,开发人员可以根据需要实现自己的类加载器。

二、类加载器的工作原理
类加载器的工作可以简化为三个步骤:

 

加载(Loading):根据类的全限定名(包括包路径和类名),定位并读取类文件的字节码。

链接(Linking):将类的字节码转换为可以在虚拟机中运行的格式。链接过程包括三个阶段:

        验证(Verification):验证字节码的正确性和安全性,确保它符合Java虚拟机的规范。

        准备(Preparation):为类的静态变量分配内存,并设置默认的初始值。

        解析(Resolution):将类的符号引用(比如方法和字段的引用)解析为直接引用(内存地址)。

初始化(Initialization):执行类的初始化代码,包括静态变量的赋值和静态块的执行。

类加载器采用了双亲委派模型(Parent Delegation Model)来加载类。即当一个类加载器需要加载类时,它会首先委派给其父类加载器加载。如果父类加载器无法加载,才由该类加载器自己去加载。这种层级关系使得类加载器能够实现类的共享和隔离,提高了代码的安全性和可靠性。

1 加载阶段

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

Class对象位置(HotSpot虚拟机)
1.在jdk1.7是在方法区中或永久代中。
2.在jdk1.8是在方法区中或元空间中。
jdk1.8中移除了永久代,转而用元空间来实现方法区。

  • 方法区其实只是一个虚拟的概念,方法区具体的实现其实是永久代元空间,1.7是永久代,1.8是元空间。
  • 元空间和永久代最大的区别就是:JDK7的永久代放在堆中并且独立与堆,JDK8的元空间完全剥离虚拟机,存在于直接内存

在这里插入图片描述

编写一个新的Java类时,JVM会帮我们编译成class对象,存放在同名的.class文件中。在运行时,当需要生成这个类的对象时,JVM会帮我们检查该类是否已经加载到内存中,若是没有加载,则把.class文件加载到内存中,若是已经加载,则根据class文件生成实例对象。

怎么理解Class对象和new出来的对象的关系?
可以把Class对象看成一个模板,每个new出来的对象都是按照
Class对象这个模板参照出来的,为啥可以参照呢?因为Class对象提供了访问方法区内数据结构的入口。

总结:
加载阶段简单来说就是:
.class文件(二进制数据)-——>读取到内存中-——>数据放到方法区-——>堆中创建对应的Class对象-——>并提供访问方法区的接口

相对于类加载的其他阶段而言,加载阶段(准确来说,是加载阶段获取类的二进制字节流的动作)是可控性最高的阶段。因为开发人员既可以使用系统提供的类加载器来完成加载,也可以定义自己的类加载来完成加载。

加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.Class类的对象。这样便可以通过该对象访问方法区中的这些数据。

加载.class文件的方式:
类的加载由类加载器完成,类的加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础。JVM提供的这些类加载器通常被称为系统类加载器,除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。通过使用不同的类加载器,可以从不同来源加载类的二进制数据。二进制数据通常有以下几种来源

  1. 从本地系统中直接加载。
  2. 通过网络下载.class文件。
  3. 从zip,jar包等归档文件中加载.class文件。
  4. 从专用数据库中提取.class文件。
  5. 将java源代码编译为.class文件。
2 验证

验证:确保被加载的类的正确性
关于验证大可不必深入但是了解类加载机制必须要知道有这么一个过程,以及知道验证就是为了确保class文件文件的字节流中包含的信息符合当前虚拟机的要求即可。
下面关于验证的内容作为了解即可。

验证是连接阶段的第一阶段,这一阶段的目的是确保class文件的字节流包含的信息符合当前虚拟机的要求,并且不会危害当前虚拟机自身的安全,验证阶段大致会完成四个阶段的检验操作。

  • 文件格式验证:验证字节流是否符合Class文件格式的规范,例如:是否以0xCAFEBABE开头,主次版本号是否在当前虚拟机的处理范围之内,常量池中的常量是否有不被支持的类型。
  • 元数据验证:对字节码描述的信息进行语义分析(注意,对比Javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求,例如这个类是否有父类,除了java.lang.Object这个类以外。
  • 字节码验证:通过程序流和数据流分析,确保程序语言是合法的,符合逻辑的。
  • 符合引用验证:确保解析操作能正确执行。
    验证阶段是非常重要的,但不是必须的,他对程序运行期间没有任何影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,来缩短虚拟机加载类的时间。
3 准备(重点

当完成字节码文件的校验之后,JVM便会开始为类变量分配内存并初始化,准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都在方法区分配

这里有两个需要注意的关键点,即内存分配的对象以及初始化的类型

内存分配的对象:要明白首先要知道Java中的变量类变量类成员变量两种类型。类变量指的是被static修饰的变量,而其他所有类型的变量都属于类成员变量。在准备阶段,JVM只会给类变量分配内存,而不会为类成员变量分配内存。类成员变量的内存分配需要等到初始化阶段才开始。

举个例子,例如下面的代码在准备阶段,只会给LeiBianLiang 属性分配内存,而不会为ChenYuanBL 属性分配内存。

public static int LeiBianLiang = 666;
public String ChenYuanBL = "jvm";

**初始化的类型:**在准备阶段,JVM会为类变量分配内存,并为其初始化(JVM只会给类变量分配内存,而不会为类成员变量分配内存,类成员变量自然这个时候也不能初始化)。但是这里的初始化指的是为变量赋予Java语言中该类型的默认值。而不是用户代码里初始化的值
例如下面的代码在准备阶段之后,LeiBianLiang的值将是0,而不是666

public static int LeiBianLiang = 666;

注意:
但如果一个变量是常量(被static final修饰的)的化,那么准备阶段,属性便会被赋予用户希望的值。例如下面的代码在准备阶段之后,ChangLiang 的值将是666,而不是0

public static final int ChangLiang = 666;

之所以被static final修饰的变量会直接赋值,而static修饰的变量会被赋予java语言类型的默认值,其实我们稍微思考一下就会明白。
两个语句的区别在于一个有final关键字修饰,另外一个没有,而final关键字在Java中代表不可改变的。意思就是说我们如果一旦对ChangLiang 赋值就不会再改变,既然一旦赋值就不会再改变,那么就必须一开始就要赋予用户希望的值。因此被final修饰的类变量再准备阶段就会被赋予想要的值,而没有被final修饰的类变量,其可能在初始化阶段或者运行阶段发生变化,所以就没有必要在准备阶段对它赋予用户想要的值。

4 解析

当通过准备阶段之后,就进入了解析阶段,解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口,字段,类方法,接口方法,方法类型,方法句柄和调用点限定符7类符号引用进行,符号引用就是一组符号来描述目标,可以是任何的字面量。

直接引用就是直接指向目标的指针,相对偏移或一个间接定位到目标的句柄。

5 初始化(重点

到了初始化阶段,用户定义的代码才真正开始执行

Java程序对类的使用方式分为两种,主动使用被动使用。一般来说,只有当对类的首次主动使用才会导致类的初始化。所以主动使用又叫做类加载过程中初始化开始的时间。
那什么是主动使用呢?包括以下六种方式

1.创建类的实例,也就是使用new关键字创建对象。
2.调用类的静态方法。
3.访问某个类或者接口的静态变量,或者对该静态变量赋值。被final和staic修饰的变量除外(是在编译器把结果放入常量池的静态字段)。
4.反射(例如Class.forName()和对象.class)。
5.初始化某个类的子类,则其父类也会被初始化。
6.Java虚拟机启动时被标明为启动类的类(JavaTest),还有就是Main方法的类会首先被初始化。

最后注意一点对于静态字段,只有直接定义这个字段的类才会被初始化(执行静态代码块),这句话在继承,多态中最为明显。

6 使用

当JVM完成初始化阶段之后,JVM便开始从入口方法开始执行用户的程序代码,使用阶段大家了解一下即可。

7 卸载

当用户程序代码执行完毕后,JVM便开始销毁创建的Class对象,最后负责运行的JVM也退出内存。

8 结束生命周期

在如下几种情况下,Java虚拟机将结束生命周期

  1. 执行了System.exit()方法。
  2. 程序正常执行结束。
  3. 程序在执行过程中遇到异常或者错误而异常终止。
  4. 由于操作系统出现错误导致Java虚拟机进程终止。

三、类加载器的使用示例

下面是一个简单的示例代码,演示了如何使用Java类加载器加载和使用类:

public class ClassLoaderExample {
    public static void main(String[] args) throws ClassNotFoundException {
        // 使用系统类加载器加载并实例化一个类
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        Class<?> clazz = classLoader.loadClass("com.example.MyClass");
        MyClass myObject = (MyClass) clazz.newInstance();
        
        // 调用加载的类的方法
        myObject.sayHello();
    }
}

class MyClass {
    public void sayHello() {
        System.out.println("Hello, World!");
    }
}

在上述示例中,我们使用系统类加载器加载并实例化了一个名为com.example.MyClass的类。然后,我们调用了该类的sayHello方法,输出了"Hello, World!"。

四、自定义类加载器
Java允许开发人员自定义类加载器,以满足特定的加载需求。自定义类加载器必须继承java.lang.ClassLoader类,并重写findClass方法。在findClass方法中,开发人员可以根据自己的规则和逻辑来加载类的字节码。

下面是一个简单的自定义类加载器的示例代码:
 

public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // 根据名称加载类的字节码
        byte[] byteCode = loadClassByteCode(name);
        // 调用defineClass方法将字节码转换为Class对象
        return defineClass(name, byteCode, 0, byteCode.length);
    }
    
    private byte[] loadClassByteCode(String name) {
        // 实现加载类字节码的逻辑
        // ...
    }
}

在上述示例中,我们自定义了一个类加载器CustomClassLoader,并重写了findClass方法。在findClass方法中,我们可以根据类的名称加载类的字节码,并通过defineClass方法将字节码转换为Class对象。开发人员可以根据具体需求实现自己的加载逻辑

总结
Java类加载器是Java虚拟机的一部分,负责加载类的字节码并转换为可执行的Java对象。类加载器采用双亲委派模型来加载类,具备层级关系共享隔离的特性。

Java提供了启动类加载器、扩展类加载器和应用程序类加载器作为主要的类加载器,开发人员也可以自定义类加载器来满足特定需求。
 

知识来源:

【基础】java类加载器有哪些_哔哩哔哩_bilibili

【Java 基础篇】Java类加载器详解_繁依Fanyi的博客-CSDN博客

 深入理解Java类加载器(ClassLoader)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kaniko在containerd中无特权快速构建并推送容器镜像

目录 一、kaniko是什么 二、kaniko工作原理 三、kanijo工作在Containerd上 基于serverless的考虑&#xff0c;我们选择了kaniko作为镜像打包工具&#xff0c;它是google提供了一种不需要特权就可以构建的docker镜像构建工具。 一、kaniko是什么 kaniko 是一种在容器或 Kube…

机器学习基础11-算法比较(基于印第安糖尿病Pima Indians 数据集)

比较不同算法的准确度&#xff0c;选择合适的算法&#xff0c;在处理机器学习的问题时是非常重要的。本节将介绍一种模式&#xff0c;在scikit-learn中可以利用它比较不同的算法&#xff0c;并选择合适的算法。你可以将这种模式作为自己的模板&#xff0c;来处理机器学习的问题…

如何备份系统?很简单,2个方法教会你!

在计算机使用过程中&#xff0c;系统故障、病毒攻击、意外损坏等问题可能导致数据丢失和系统无法正常运行。为了保障数据安全和系统稳定&#xff0c;如何备份系统是至关重要的。本文将介绍备份系统的2个方法&#xff0c;帮助用户轻松备份系统&#xff0c;确保数据的安全和系统的…

什么是网络中的服务质量 (QoS),其相关技术和关键指标有哪些?

QoS&#xff08;Quality of Service&#xff0c;服务质量&#xff09;指一个网络能够利用各种基础技术&#xff0c;为指定的网络通信提供更好的服务能力&#xff0c;是网络的一种安全机制&#xff0c;是用来解决网络延迟和阻塞等问题的一种技术。QoS的保证对于容量有限的网络来…

MES管理系统解决方案,助力汽配企业打造透明化管理

随着汽车行业的不断发展&#xff0c;汽配行业面临着越来越严格的质量要求和生产效率提升挑战。为了满足这些需求&#xff0c;汽配企业需要实现生产过程的透明化和精细化。MES管理系统解决方案作为生产过程的核心管理系统&#xff0c;可以为汽配企业提供全面的解决方案&#xff…

ubuntu22.04安装搜狗输入法后始终无法输入中文

这次真的整我很久很久&#xff0c;我都不想用搜狗输入法了&#xff0c;结果无意间还是被我解决了。 ubuntu22.04安装搜狗输入法的步骤参考官网给的文档就行&#xff0c;这里我只说我的为啥输入不了中文 点击Fcitx配置 把搜狗输入法个人版放在第一位就行(我的系统语言是中文&am…

思维导图的作用有哪些?了解一下这几个作用

思维导图的作用有哪些&#xff1f;思维导图是一种以图形和颜色为主要表现形式的思维工具&#xff0c;它可以帮助人们更好地组织和表达思想。它的作用有很多&#xff0c;下面就给大家简单介绍一下。 1、帮助记忆 思维导图可以将大量信息整合到一个图形中&#xff0c;这有助于人…

一次由摔碎手机屏幕导致的急速搬家

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 封面 / 姝琦midjourney 产品统筹 / bobo 想问问大家&#xff0c;都在什么情况下搬过家&#xff1f; 有的时候搬家是迫不得已&#xff0c;房东突然发难&#xff1b; 有的时候搬…

MyBatis分页插件PageHelper的使用及MyBatis的特殊符号---详细介绍

一&#xff0c;分页的概念 分页是一种将大量数据或内容分割成多个页面以便逐页显示的方式。在分页中&#xff0c;数据被分割成一定数量的页&#xff0c;每页显示一部分数据或内容&#xff0c;用户可以通过翻页或跳分页是一种将大量数据或内容分割成多个页面以便逐页显示的方式。…

深入浅出 RPC框架

RPC 框架分层设计 01 基本概念 1.1 本地函数调用 以上步骤只是为了说明原理。事实上编译器经常会做优化&#xff0c;对于参数和返回值少的情况会直接将其存放在寄存器&#xff0c;而不需要压栈弹栈的过程&#xff0c;甚至都不需要调用call&#xff0c;而直接做inline操作 1.2 远…

Forrester首次面向中国的开源报告:阿里云在云原生领域开源布局最全面

Forrester 于近期发布了《Navigate The Cloud-Native Ecosystem In China, 2023》&#xff0c;报告概述了中国云原生领域的开源项目对构建云原生生态的促进作用&#xff0c;这些开源项目正深刻影响着企业的技术决策者以何种策略拥抱云原生这一现代 IT 基础设施的核心。 报告表…

SMC状态机 讲解2 从模型到SMC

SMC状态机 讲解2 从模型到SMC 1、实例化有限状态机&#xff08;FSM)2、简单转换 Simple Transition3、外部环回转换 External Loopback Transition4、内部环回转换 Internal Loopback Transition5、转换动作6、转换Guard7、转换参数8、Entry 和 Exit动作9、Push 转换10、Pop转换…

AI加持,创意设计效率百倍提升,探秘背后的数字化魔法

在当今创新潮流不断涌现的时代&#xff0c;人工智能正以惊人的速度和深度赋能各行各业&#xff0c;食品包装设计界也已来到了一个“拼创意、拼二创和拼审美”的时代。有了AI的加入&#xff0c;设计界正迎来一股AI创意风暴&#xff0c;不仅颠覆了设计流程&#xff0c;更为食品包…

机器学习教程(非常详细)从零基础入门到精通,看完这一篇就够了

一、机器学习的定义 从广义上来说&#xff0c;机器学习是一种能够赋予机器学习的能力以此让它完成直接编程无法完成的功能的方法。但从实践的意义上来说&#xff0c;机器学习是一种通过利用数据&#xff0c;训练出模型&#xff0c;然后使用模型预测的一种方法。 “训练”与“…

在leangoo免费敏捷工具中如何批量设置成员权限

Leangoo领歌是一款永久免费的专业敏捷开发管理工具&#xff0c;提供端到端敏捷研发管理解决方案&#xff0c;涵盖敏捷需求管理、任务协同、进展跟踪、缺陷管理、统计度量等。 包括小型团队敏捷开发&#xff0c;规模化敏捷SAFe&#xff0c;Scrum of Scrums大规模敏捷。其功能/解…

java包的package-info.java文件

Java包的下面可以放一个package-info.java文件&#xff0c;在这个文件中声明包&#xff0c;在注释中增加包的介绍信息。这样javadoc工具就可以优先从这个文件中获取包的介绍信息。 例如Java工程&#xff0c;在包com.thb下面有package-info.java文件&#xff1a; package-inf…

优秀产品奖!移远5G RedCap模组,让5G真正“轻”下来

8月24日&#xff0c;在通信世界全媒体主办的“5G RedCap技术与物联网应用创新研讨会”上&#xff0c;“5G RedCap优秀产品和解决方案”获奖名单发布&#xff0c;移远通信5G RedCap模组Rx255C系列以其在创新性、实用性、经济性、成熟性等方面的综合领先优势&#xff0c;获此殊荣…

Spring Boot进阶(58):集成PostgreSQL数据库及实战使用 | 万字长文,超级详细

1. 前言&#x1f525; PostgreSQL是一种广泛使用的开源关系型数据库&#xff0c;具有可靠性高、性能优异、拥有丰富的数据类型和扩展等优点&#xff0c;越来越多的企业和开发者开始使用它来存储和管理数据。而Spring Boot是一种快速开发的框架&#xff0c;可以简化开发过程并提…

照片怎么转换成pdf?几种照片转pdf方法看一看

照片怎么转换成pdf&#xff1f;照片转换成PDF是一个非常有用的技能&#xff0c;可以将多张照片合并为一个文件&#xff0c;方便保存和分享。现在也有很多方法可以将照片转换为PDF&#xff0c;下面就给大家介绍几种转换方法。 转换方法一&#xff1a;迅捷PDF转换器 这是一款功能…

GPT---1234

GPT:《Improving Language Understanding by Generative Pre-Training》 下载地址:https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdfhttps://cdn.openai.com/research-covers/language-unsupervised/language_understa…