深入理解Java虚拟机:Java类的加载机制

news2025/6/30 4:55:19

本篇内容包括:Java 类的加载机制(Jvm 结构组成、Java 类的加载)、类的生命周期(加载-验证-准备-解析-初始化-使用-卸载)、类加载器 以及 双亲委派模型。

一、Java 类的加载机制

1、 Jvm 结构组成

Jvm 整体组成可分为四个部分:类加载器、运行时数据区(Runtime Data Area)、执行引擎(Execution Engine)、本地库接口(Native Interface)

  • 类加载器:负责从字节码(Class)文件中,加载 class 信息到运行时数据区的方法区;
  • 运行时数据区:存放 Jvm 在执行 Java 程序时相关数据的区域;
  • 执行引擎:将字节码翻译成底层系统指令再交由 CPU 去执行;
  • 本地库接口:执行过程中可能需要调用到其他语言(比如 C 语言)的本地接口。

PS:Javac 是收录于 Jdk 中的 Java 语言编译器。该工具可以将后缀名为 .java 的源文件编译为后缀名为 .class 的可以运行于 Java 虚拟机的字节码。

程序在被执行之前, Java 代码会被先转换成字节码(.class 文件), Jvm 首先通过一定的方式类加载器(ClassLoader)把字节码文件加载到内存中运行时数据区(Runtime Data Area),而字节码文件是 Jvm 提供的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine)将字节码翻译成底层系统指令再交由 CPU 去执行,而这个过程中需要调用其他语言的接口本地库接口(Native Interface)来实现整个程序的功能,这就是这 4 个主要组成部分的职责与功能。

而我们通常所说的 Jvm 组成指的是运行时数据区,因为通常需要程序员调试分析的区域就是运行时数据区,或者更具体的来说就是运行时数据区里面的堆(Heap)模块!

2、Java 类的加载

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

类加载器并不需要等到某个类被首次主动使用时再加载它, Jvm 规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了 .class 文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误( LinkageError 错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。

加载.class 文件的方式:

  • 从本地系统中直接加载
  • 通过网络下载 .class 文件
  • 从 zip、jar 等归档文件中加载 .class 文件
  • 从专有数据库中提取 .class 文件
  • 将 Java 源文件动态编译为 .class 文件
  • 由其他文件生成

二、Java 类的生命周期

类从被加载到 Jvm 内存中开始到卸载出内存为止,生命周期分为7个阶段:加载-验证-准备-解析-初始化-使用-卸载。(或分为5个阶段,把 验证-准备-解析 分为连接阶段)

1、加载

加载过程就是把 class 字节码文件载入到虚拟机中,至于从哪儿加载,虚拟机设计者并没有限定,你可以从文件、压缩包、网络、数据库等等地方加载 class 字节码。

  • 通过一个类的全限定名来获取其定义的二进制字节流;
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
  • 在Java堆中生成一个代表这个类的 java.lang.Class 对象,作为对方法区中这些数据的访问入口

2、验证(连接阶段的第一步):确保被加载的类的正确性

这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:文件格式验证、元数据验证、字节码验证、符号引用验证

验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用 -Xverifynone 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

3、准备(连接阶段的第二步):为类的静态变量分配内存,并将其初始化为默认值

准备阶段的工作就是为类的静态变量分配内存并设为 Jvm 默认的初值,对于非静态的变量,则不会为它们分配内存。静态变量的初值为 Jvm 默认的初值,而不是我们在程序中设定的初值。(仅包含类变,不包含实例变量)

4、解析(连接阶段的第三步):把类中的符号引用转换为直接引用

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

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

5、初始化:为类的静态变量赋予正确的初始值

主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:

  1. 声明类变量是指定初始值;
  2. 使用静态代码块为类变量指定初始值

Jvm初始化步骤:

  1. 假如这个类还没有被加载和连接,则程序先加载并连接该类

  2. 假如该类的直接父类还没有被初始化,则先初始化其直接父类

  3. 假如类中有初始化语句,则系统依次执行这些初始化语句

类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:

  1. 创建类的实例,也就是new的方式
  2. 访问某个类或接口的静态变量,或者对该静态变量赋值
  3. 调用类的静态方法
  4. 反射(如 Class.forName(“com.shengsiyuan.Test”) )
  5. 初始化某个类的子类,则其父类也会被初始化
  6. Java虚拟机启动时被标明为启动类的类( JavaTest ),直接使用 java.exe 命令来运行某个主类

三、类加载器

类加载器是负责将可能是网络上、也可能是磁盘上的 .class 文件加载到内存中。并为其生成对应的 java.lang.Class 对象。一旦一个类被载入 Jvm 了,同一个类就不会被再次加载。那么怎样才算是同一个类?在 Java 中一个类用其全限定类名(包名和类名)作为其唯一标识,但是在 Jvm 中,一个类用其全限定类名和其类加载器作为其唯一标识。也就是说,在 Java 中的同一个类,如果用不同的类加载器加载,则生成的 .class 对象认为是不同的。

当 Jvm启动时,会形成由三个类加载器组成的初始类加载器层次结构:

  • 启动类加载器(Bootstrap ClassLoader):是嵌在 Jvm 内核中的加载器,该加载器是用 C++ 语言写的,主要负载加载 JAVA_HOME/lib 下的类库,启动类加载器无法被应用程序直接使用;
  • 扩展类加载器(Extension ClassLoader):该加载器器是用JAVA编写,且它的父类加载器是 Bootstrap,是由 sun.misc.Launcher$ExtClassLoader实现的,主要加载 JAVA_HOME/lib/ext 目录中的类库。开发者可以这几使用扩展类加载器;
  • 系统类加载器(App ClassLoader):也称为应用程序类加载器,负责加载应用程序 classpath 目录下的所有 .jar 和 .class 文件。它的父加载器为 Extension ClassLoader。

上述三种类加载器的层次关系如下:

Ps:类加载器的体系并不是“继承”体系,而是委派体系,大多数类加载器首先会到自己的 parent 中查找类或者资源,如果找不到才会到自己本地查找。类加载器的委托行为动机是为了避免相同的类被加载多次。

五、双亲委派模型

1、双亲委派模型

如果以上三种类加载器不能满足要求的话,程序员还可以自定义类加载器(继承 java.lang.ClassLoader 类)

它们的层级关系即 自定义类加载器 -> 应用程序加载器 -> 扩展加载器 -> 启动类加载器,这种层次关系被称作为双亲委派模型:如果一个类加载器收到了加载类的请求,它会先把请求委托给上层加载器去完成,上层加载器又会委托上上层加载器,一直到最顶层的类加载器;如果上层加载器无法完成类的加载工作时,当前类加载器才会尝试自己去加载这个类。

2、双亲委派模式优势

  • 采用双亲委派模式的是好处是 Java 类随着它的类加载器一起具备了一种带有先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子 ClassLoader 再加载一次;
  • 其次是考虑到安全因素,Java 核心 api 中定义类型不会被随意替换,假设通过网络传递一个名为 java.lang.Integer 的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心 Java API 发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的 java.lang.Integer,而直接返回已加载过的 Integer.class,这样便可以防止核心 API 库被随意篡改;
  • 可能你会想,如果我们在 classpath 路径下自定义一个名为 java.lang.SingleInterge 类呢?该类并不存在 java.lang 中,经过双亲委托模式,传递到启动类加载器中,由于父类加载器路径下并没有该类,所以不会加载,将反向委托给子类加载器加载,最终会通过系统类加载器加载该类。但是这样做是不允许,因为 java.lang 是核心 API 包,需要访问权限,强制加载将会报出异常 java.lang.SecurityException: Prohibited package name: java.lang 所以无论如何都无法加载成功的。

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

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

相关文章

坤坤音效键盘(Python实现)

文章目录坤坤音效键盘说明坤坤音效键盘效果展示代码实现安装第三方库准备音频监听键盘播放音频编写逻辑引入线程打包成exe程序坤坤音效键盘说明 坤坤音效键盘说明: 单独按下 j、n、t、mj、n、t、mj、n、t、m 按键,会对应触发 “鸡”、“你”、“太”、…

科技视界杂志科技视界杂志社科技视界编辑部2022年第21期目录

科技视界杂志科技视界杂志社科技视界编辑部2022年第21期目录 科普论坛《科技视界》投稿:cnqikantg126.com 天敌昆虫——让农业生产更安全 季香云; 1-3 储粮昆虫三维模型Web可视化技术研究与应用 阎磊;马宏琳;李亮;李鹏翔;王义超; 4-6 科学实验 非均匀催…

wy的leetcode刷题记录_Day33

wy的leetcode刷题记录_Day33 时间:2022-11-4 目录wy的leetcode刷题记录_Day33754. 到达终点数字题目介绍思路代码收获199. 二叉树的右视图题目介绍思路代码收获754. 到达终点数字 今天的每日一题是:754. 到达终点数字 题目介绍 在一根无限长的数轴上…

CSS:变量函数var和自定义属性

文章目录CSS变量var()函数CSS变量 CSS变量分为两部分:变量声明和变量使用。 变量的声明是由CSS自定义属性和对应的属性朱组成的,比如: :root {--custom-color: deepskyblue;}在这段代码中,–custom-color是属于css的自定义属性名…

方法的使用

目录 1. 举例说明什么叫方法 2. 方法概念及使用 2.1 什么是方法(method) 1.2 方法定义 1.3 方法调用的执行过程 1.4 实参和形参的关系(重要) 2. 方法重载 2.1 为什么需要方法重载 2.3 方法签名 3. 递归 递归执行过程分析 1. 举例说明什么叫方法 我们利用面向对象的方…

2022年特色小镇行业研究报告

第一章 行业概况 特色小镇是在几平方公里土地上集聚特色产业、生产生活生态科技相融合、不同于行政建制镇和产业园区的创新创业平台。根据类型的不同,特色小镇可以分为三类,即产业类、社区类和旅游类。 产业类:通过招商引资吸引企业进入&…

门控循环单元(GRU)【动手学深度学习v2】

理论 候选隐藏状态。 圆圈 表示 按元素乘法。 这里面的 这个符号值得是 按元素相乘。 Rt理解为 和Ht 长度一样的一维向量。(这么理解) 这里如果Rt长的像0的话,那么乘出来的结果,就也像0。 要是像0 的话,相当于是说…

文件操作之文件系统

目录 一 磁盘 1 磁盘的物理结构 2 磁盘在物理结构上如何存储数据 CHS寻址 3 从物理结构到抽象结构 LBA寻址 4管理 二 块组 boot block super block inode table data blocks block bitmap GDT:Global Descriptor Table 块组描述符 三 文件名和目录之…

网课查题接口搭建

网课查题接口搭建 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 查题校园题库:查题校园题库后台(点击跳…

字符串匹配算法(C/Java实现)

目录BF算法C语言实现Java实现KMP算法Java实现C语言实现next[]数组的优化BF算法 BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,…

R语言代做实现:混合正态分布EM最大期望估计法

全文链接:http://tecdat.cn/?p4815 原文出处:拓端数据部落公众号 因为近期在分析数据时用到了EM最大期望估计法这个算法,在参数估计中也用到的比较多。然而,发现国内在R软件上实现高斯混合分布的EM的实例并不多,大多…

Linux系统下实现开机自动加载驱动模块

在使用模块化加载驱动时,若系统内部存在同类别设备驱动,可能会出现无法加载我们添加的动态模块,比如Linux系统内置了CDC驱动,当我们使用兼容CDC和VCP驱动USB转串口芯片时,就会出现上电出现的是CDC串口,从而…

vue3 组件响应式v-model 失效,实践踩坑,一文搞懂组件响应式原理,对初学者友好

文章目录前情提要实战解析最后前情提要 vue3的v-model已经有了变化,假如你还不知道其中细节,看完这篇文章你就完全明白了,我以踩坑的场景来进行解析。起因是在我的项目中需要一个输入框组件,这个组件用来根据输入异步查询系统内已…

Python编程 基础数据类型

作者简介:一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言: 一.Python基础数据类型 1.为什么会有数据类型?&am…

公共云和私有云之间的区别

目前,越来越多的公司正在调整云服务来运行他们的应用程序。其实,有不同类型的云部署模型来满足客户的不同需求。云部署模型分为三种类型:公有云、私有云和混合云(公有云和私有云的混合)。在本文中,我们将对公共云和私有云之间的区…

【数据结构】单链表——单链表的定义及基本操作的实现(头插、尾插、头删、尾删、任意位置的插入与删除)

🧑‍💻作者: 情话0.0 📝专栏:《数据结构》 👦个人简介:一名双非编程菜鸟,在这里分享自己的编程学习笔记,欢迎大家的指正与点赞,谢谢! 单链表前言…

分享30个PHP源码,总有一款适合你

链接:https://pan.baidu.com/s/1dVbUn5YFMOze4J-K8sCAXQ?pwdeinu 提取码:einu 下面是文件的名字,我放了一些图片,文章里不是所有的图主要是放不下...,大家下载后可以看到。 Emlog for SAE 适合新浪sae使用的个人博客…

网关Gateway-快速上手

gateway网关官方文档: https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/# 网关的概念 网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等。 Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关…

Java:修改Jar的源码,并上传Nexus私有仓库,替换jar版本

第一步:修改jar包源代码 建一个全类名一模一样的类,然后把要修改的类的代码复制过去,然后编译生成class。然后拿编译后的class覆盖到jar中对应的位置 第二步:上传nexus jar文件,pom文件:在本地仓库中可以…

Linux操作系统~进程有哪些状态?

目录 R状态 S/D状态 什么是D状态 T状态 X状态 Z状态 什么是等待队列,什么是运行队列,什么是挂起/阻塞,什么叫唤醒进程 对比宏观上操作系统的三种状态 从操作系统宏观的概念上讲,进程有三种状态,就绪态&#xff0…