Java类加载过程面试总结

什么是Java的类加载机制

Java 虚拟机一般使用 Java 类的流程为:首先将开发者编写的 Java 源代码(.java文件)编译成 Java 字节码(.class文件),然后类加载器会读取这个 .class 文件,并转换成 java.lang.Class 的实例。有了该 Class 实例后,Java 虚拟机可以利用 newInstance 之类的方法创建其真正对象了。

简单来说类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。

堆上的class对象和方法区有什么关系

堆上的class对象和方法区之间有密切的关系。在Java虚拟机中,每个类只有一个class对象,该对象被存储在堆中。同时,该对象中包含了类的所有信息,包括类的名称、父类、接口、成员变量和方法等等。这些信息都存储在方法区中。因此,可以说堆上的class对象和方法区是相互依存的关系。堆上的class对象是方法区中类信息的实体化表示。方法区中的类信息需要通过堆上的class对象来获取,而堆上的class对象依赖于方法区中的类信息来构建完整的类对象。

这个class对象是做什么的

在Java中,每个类的定义都会被编译成一个class文件,这个class文件中包含了该类的基本信息,例如类的名字、方法、变量等。

class对象是一个Java虚拟机在运行时创建的表示类的实例对象,它包含了一个类的完整信息,如类的构造方法、成员变量、成员方法、注解、访问修饰符等等。

class对象在Java程序中被广泛使用。特别是在反射中,class对象被用来获取某个类的信息、创建该类的对象、调用该类的方法等等。通过class对象,Java程序可以在运行时动态地获取类的信息和创建对象实例。因此,class对象在Java程序开发中具有非常重要的作用。

方法区是做什么的

方法区是Java虚拟机的一个重要组成部分,它用来存储类的信息、常量、静态变量等数据。具体来说,方法区的作用包括以下几个方面:

  1. 存储类信息:方法区中存储了类的定义信息,包括类的名称、继承信息、接口信息、方法和变量等信息,这些信息在JVM启动时就已经被加载到方法区中。

  2. 存储常量池:方法区中还存储了每个类的常量池,用于存储字面量和符号引用等信息。

  3. 存储静态变量:在程序运行时,所有的静态变量和类变量都被存储在方法区中,这些变量的值可以在整个程序运行过程中被访问和修改。

  4. 存储编译后的代码:在JVM解析Java类文件时,会将其中的字节码存储在方法区中,并在需要执行时将其加载到内存中执行。

总之,方法区是Java虚拟机的一部分,它用于存储类的定义、常量、静态变量和编译后的代码等信息。这些信息在程序运行期间都可以被访问和使用。了解方法区的作用可以帮助我们更好地理解Java虚拟机的工作原理。

类的生命周期

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段。其中验证、准备、解析3个部分统称为连接。

在这里插入图片描述

类加载过程

Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚拟机是如何加载这些 Class 文件呢?

系统加载 Class 类型的文件主要三步:加载->连接->初始化。连接过程又可分为三步:验证->准备->解析。

加载

类加载的第一个阶段,在这个阶段,虚拟机主要完成以下3件事:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流。
  2. 将字节流中所代表的静态数据结构转化为方法区的运行时数据结构。
  3. 在内存中生成一个代表该类的java.lang.Class对象,作为方法区中这个类各种数据的访问入口。
解释一下这句话:在内存中生成一个代表该类的java.lang.Class对象,作为方法区中这个类各种数据的访问入口。

在Java中,每个类都有一个与之对应的java.lang.Class对象,该对象代表了该类的描述信息和运行时状态。这个Class对象是在解析和加载类文件时在内存中生成的,并作为一个入口,提供了访问方法区中这个类各种数据的接口。

具体来说,Class对象在方法区中存储了该类的信息,包括类的名称、父类、接口、成员变量和方法等。创建了Class对象之后,程序就可以通过这个对象来访问方法区中这个类的各种数据,包括静态变量、方法、构造函数等。此外,在反射中,也可以通过Class对象来获取和修改类的信息,实现动态生成对象和执行方法的功能。

总之,通过在内存中生成一个代表该类的java.lang.Class对象,程序可以访问方法区中这个类的各种数据和信息,从而实现了一种非常重要的功能,即反射。在Java程序开发中,反射是一种常见的编程技术,它可以使程序具有更大的灵活性和可扩展性。

验证

连接阶段的第一步,该阶段主要目的是为了确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。从整体上看,这个阶段大致会完成下面四个阶段的检验动作:文件格式验证、元数据验证、字节码验证和符号引用验证

在这里插入图片描述

准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些类变量所使用的内存都将在方法区中分配。

对于该阶段,需要注意以下几点:

  1. 这个阶段进行内存分配的仅包括类变量( Class Variables ,即静态变量,被 static 关键字修饰的变量,只与类相关,因此被称为类变量),而不包括实例变量。实例变量会在对象实例化时随对着象一起分配在Java堆中。
  2. 从概念上讲,类变量所使用的内存都应当在方法区中进行分配。
    在JDK 1.7 之前,HotSpot 使用永久代来实现方法区的时候,实现是完全符合这种逻辑概念的。 而在 JDK 1.7 及之后,HotSpot 已经把原本放在永久代的字符串常量池、静态变量等移动到堆中,这个时候类变量则会随着 Class 对象一起存放在 Java 堆中。
    具体细节请移步观看我的另一篇博客——JVM面试题详解系列——JVM内存区域详解。
  3. 这里所设置的初始值通常情况下是数据类型默认的零值(如 0、0L、null、false 等),比如我们定义了public static int test = 6 ,那么 test 变量在准备阶段的初始值就是 0 而不是 6(初始化阶段才会赋值)。特殊情况:如果给 test 变量加上了 final 关键字public static final int test = 6 ,那么准备阶段 test 的值就被赋值为 6。

解析

解析阶段是虚拟机将常量池中的符号引用替换为直接引用的过程。解析动作主要针对接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符这7类符号应用进行。

在程序执行方法时,系统需要明确知道这个方法所在的位置。Java 虚拟机为每个类都准备了一张方法表来存放类中所有的方法。当需要调用一个类的方法的时候,只要知道这个方法在方法表中的偏移量就可以直接调用该方法了。通过 解析操作 符号引用就可以转变为目标方法在类中方法表的位置,从而使得方法可以被调用。

综上,解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,也就是得到类或者字段、方法在内存中的指针或者偏移量。

这些符号引用是什么?什么时候生成的?

符号引用是指在Java类文件中以字符串形式出现的、用于描述被引用的目标(如类、方法、字段)的符号。该符号代表了目标的名称、类型和相关描述符。具体来说,在Java类文件中出现的符号引用包括以下几种:

  1. 类的符号引用:表示类的名称和路径。

  2. 字段符号引用:表示字段的名称和类型。

  3. 方法符号引用:表示方法的名称、参数类型和返回类型。

符号引用的生成是在编译Java源代码时完成的,编译器根据源代码中出现的类型和名称信息生成符号引用,并将其保存到类文件的常量池中。当类文件被加载到JVM中时,VM会根据常量池中的符号引用信息查找类与方法执行,并将符号引用转化成直接引用。

总之,符号引用是Java类文件中一种重要的元数据,在Java源代码编译为字节码文件时生成。在类文件加载到JVM时,常量池中的符号引用会被解析成直接引用,使得程序可以正确地执行类和方法。

符号引用

符号引用是一组用来描述所引用目标的符号,属于编译原理方面的概念,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。

直接引用

直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。直接引用可以帮助程序直接定位到所需的对象。

符号引用和直接引用的详细介绍请移步观看我的另一篇博客——JVM面试题详解系列——Java中几种常量池的区分。

初始化

初始化阶段是执行类构造器 <clinit> ()方法的过程,是类加载的最后一步,到了这一步,Java虚拟机才开始真正执行类中定义的 Java 程序代码(字节码)。在准备阶段,类变量已经赋过一次系统要求的初始零值,而在初始化阶段,则会根据程序员通过程序制定的主观计划去初始化类变量和其他资源。需要注意的是,<clinit>()不是程序员在 Java 代码中直接编写的方法,而是由 Javac 编译器自动生成的

介绍一下 <clinit> ()方法

<clinit> ()是Java中的一个特殊方法,它是类的初始化方法,也称为类构造器,用于初始化类的静态变量和静态代码块。该方法在JVM加载一个类时自动被调用,实际上是编译器在编译阶段由编译器自动为类添加的静态方法

在类的<clinit> ()方法中,可以包含类的静态变量、静态代码块和静态方法的初始化代码。这些代码会在类加载过程中执行,保证了类的静态变量和静态代码块的正确初始化。

<clinit> ()方法由编译器自动生成,其代码由静态字段和静态代码块组成,按照在源代码中出现的顺序生成,因此它的执行顺序是严格按照静态代码出现的顺序执行的。

需要注意的是,类的<clinit> ()方法是线程安全的,它会在类被加载的过程中被调用一次,保证了类的静态成员的正确初始化。

总之,<clinit> ()是Java中的一个特殊方法,用于初始化类的静态变量、静态代码块和静态方法。该方法由编译器自动生成,保证了类的静态成员在类加载时正确的初始化,是Java中一个很重要的机制。

卸载

卸载类即该类的 Class 对象被 GC。

在Java虚拟机(JVM)中,卸载类需要满足以下三个要求:

  1. 该类的所有实例对象都已经被GC回收:在垃圾回收期间,JVM会对堆上的对象进行回收。只有当一个类的所有实例对象都已经被GC回收时,才能卸载该类。

  2. 该类的Class对象不存在引用:在Java虚拟机中,每个类都有一个对应的Class对象。如果该类的Class对象存在引用,比如被其他类的成员变量、方法等持有引用,就不能卸载该类。

  3. 该类的所有Classloader都已经被GC回收:在Java虚拟机中,每个类的加载器在加载类后会被持有引用。如果该类的加载器存在引用,就不能卸载该类。

只有当这三个要求全部满足时,JVM才能卸载一个类。这个过程是由垃圾回收器自动执行的,无法手动触发。

值得注意的是,类的卸载是一个非常罕见的事件。在大多数情况下,卸载类不是必须的,因为JVM会在内存不足时触发垃圾回收,回收不再使用的对象。只有在特殊的应用场景才需要考虑卸载类的问题,例如在OSGi、动态代码生成等高级应用场合。

简化版:

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

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

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

相关文章

05.List的介绍

1. List 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection。 Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下所示&#xff1a; Iterable也是一个接口&#xff0c;表示实现该接口的类是可以逐个元素进行遍…

仿真与测试:单元测试与Test Harness

本文描述单元测试的概念&#xff0c;以及Test Harness建立的方法和简单的单元测试过程。 文章目录1 单元测试1.1 场景举例1.2 简单的测试方法2 Test Harness建立2.1 模型配置2.2 创建Test Harness3 总结1 单元测试 单元测试&#xff0c;简单来说就是在Simulink模型中只测试一小…

63-哈希表

目录 1.哈希表的概念 2.哈希函数的概念 3.哈希函数的设计 3.1.key为整型时哈希函数的设计 3.1.1.普通整数 3.1.2.负整数 3.1.3.大整数 PS&#xff1a;哈希函数设计的3个要求&#xff1a; PS&#xff1a;2种类型的哈希函数&#xff08;大整数&#xff09; 3.2.key为其…

【数据结构】树与二叉树的基本概念及性质

目录 一、树的基本概念 1️⃣树的定义 2️⃣基本术语 3️⃣树的性质 二、二叉树的概念 1️⃣二叉树的定义 2️⃣特殊二叉树 3️⃣二叉树的性质 参考资料 一、树的基本概念 1️⃣树的定义 数据结构中的树是什么❓ 树是 个结点的有限集。有且仅有一个特定的称为根(上图A结点…

C++ [内存管理]

本文已收录至《C语言》专栏&#xff01; 作者&#xff1a;ARMCSKGT 目录 前言 正文 计算机中内存分布 C语言的内存管理 内存申请函数 内存释放函数 C内存管理 new操作符 delete操作符 特性总结 注意 原理探究 operator new和operator delete函数 operator new的底…

【C++】STL之string的使用和模拟实现

初阶的C语法和基本的类和对象我们已经学过了&#xff0c;下面我们会步入一段新的旅程。本章我们将初步了解STL(标准模板库)&#xff0c;并且深入探讨其中一个非常重要的容器———string。 目录 &#xff08;一&#xff09;STL简介&#xff08;了解即可&#xff09; &#xf…

Hashtable、HashMap、ConcurrentHashMap的区别

作者&#xff1a;爱塔居 专栏&#xff1a;JavaEE 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起进步。 Hashtable和HashMap、ConcurrentHashMap 之间的区别? HashMap:线程不安全&#xff0c;key允许为null Hashtable:线程安全&#xff0c;使用synchronized锁Hashta…

2.4 特征工程

2.4 特征工程 李沐 B站:https://space.bilibili.com/1567748478/channel/collectiondetail?sid=28144 课程主页:https://c.d2l.ai/stanford-cs329p/ 1. 为什么需要特征工程: 特征工程 数据集进行特征提取,以使机器学习模型在对经过特征工程处理过的数据进行学习时可以更快…

(02)基础强化:面向对象,变量作用域,封装,继承,虚方法,可访问性

一、面向对象概念复习 1、什么是面向对象&#xff1f;OOP&#xff08;Object-Oriented Programming&#xff09; 一种分析问题的方式&#xff0c;增强了程序的可扩展性。 OOP面向对象编程 OOA面向对象分析 OOAD面向对象分析与设计&#xff08;…

Redis管道(pipeline)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言1、管道(pipeline)的基本概念2、管道实操3、小总结前言 在正式讲解Redis管道之前&#xff0c;先引入一个面试题&#xff1a; 如何优化频繁命令往返造成的性能瓶…

【Hello Linux】线程控制

作者&#xff1a;小萌新 专栏&#xff1a;Linux 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;简单介绍linux中的线程控制 线程控制线程创建线程等待线程终止线程分离线程id和进程地址空间布局线程创建 我们可以通过下面pthread_c…

蓝桥杯基础14:BASIC-1试题 闰年判断

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 问题描述 给定一个年份&#xff0c;判断这一年是不是闰年。 当以下情况之一满足时&#xff0c;这一年是闰年&#xff1a; 1. 年份…

Java面向对象 - 封装、继承和多态的综合练习(答案+知识点总结)第1关:封装、继承和多态进阶(一)+ 第2关:封装、继承和多态进阶(二)

目录 第1关&#xff1a;封装、继承和多态进阶&#xff08;一&#xff09; 报错总结 & 注意事项&#xff1a; 第2关&#xff1a;封装、继承和多态进阶&#xff08;二&#xff09; 源码&#xff1a; 报错总结 & 注意事项&#xff1a; 思维导图免费制作网站&#xf…

软考软件设计师下午试题一

数据流图基本图形元素 外部实体 外部系统是当前系统之外的系统 数据存储 在里面存储数据后还能取出来用 跟实体没有关系&#xff0c;他负责存储加工的数据或者提供数据给加工 加工 灰洞的解释比如输入需要两个才能得到输出的&#xff0c;但是他只输入了一个就是灰洞 数…

Matlab傅里叶级数展开(附结果图)

Matlab傅里叶级数展开&#xff08;附结果图&#xff09; 代码下载链接 代码下载链接 代码下载链接 如下图所示&#xff1a;

“唯一靶点”的华堂宁会成控糖爆品吗?

一上市&#xff0c;两次“断货”的货华堂宁有爆品那味儿了。 2022年10月28日华领医药-B&#xff08;02552.HK&#xff09;公告华堂宁&#xff08;多格列艾汀&#xff09;正式进入商业化&#xff0c;一周后各个渠道便进入到了断货和限售的状态。 对于一个不在传统九大降糖药品…

元宇宙与网络安全

元宇宙是一种虚拟现实空间&#xff0c;用户可以在计算机生成的环境中进行互动。元宇宙的应用范围很广&#xff0c;比如房地产&#xff0c;医疗&#xff0c;教育&#xff0c;军事&#xff0c;游戏等等。它提供了更具沉浸感的体验&#xff0c;更好地现实生活整合&#xff0c;以及…

组件、套件、 中间件、插件

组件、套件、 中间件、插件 组件 位于框架最底层&#xff0c;是由重复的代码提取出来合并而成。组件的本质&#xff0c;是一件产品&#xff0c;独立性很强&#xff0c;组件的核心&#xff0c;是复用&#xff0c;与其它功能又有强依赖关系。 模块 在中台产品和非中台产品中&…

C语言程序环境和预处理

文章目录程序的翻译环境和执行环境详解编译和链接翻译环境编译本身也分为几个阶段预处理编译汇编链接段表符号表的合并预处理详解预定义符号#define#define 定义标识符#define定义宏#define替换规则#和#### 的作用带副作用的宏参数宏和参数的对比宏和函数的一个对比命名约定#un…

FastestDet:比yolov-fastest更快!更强!全新设计的超实时Anchor-free目标检测算法

本篇文章转自于知乎——qiuqiuqiu,主要设计了一个新颖的轻量级网络! 代码地址:https://github.com/dog-qiuqiu/FastestDet 1 概述 FastestDet是设计用来接替yolo-fastest系列算法,相比于业界已有的轻量级目标检测算法如yolov5n, yolox-nano, nanoDet, pp-yolo-tiny, Fast…