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

JVM类的加载和类的加载器

JVM类的加载和类的加载器

一.类的加载过程

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

1.加载

一般来说加载分为以下几步:

  1. 通过一个类的全限定名获取此类的二进制字节流
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口
加载.class文件的方式
  • 从本地系统中直接加载

  • 通过网络获取,典型场景: web Applet

  • 从zip压缩包中读取,成为口后jar、war格式的基础

  • 运行时计算生成,使用最多的是:动态代理技术由其他文件生成,典型场景: JSP应用

  • 从专有数据库中提取.class文件,比较少见

  • 从加密文件中获取,典型的防class文件被反编译的保护措施

2.链接

2.1验证(Verify)
  • 目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。
  • 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证
2.2准备(Prepare)
  • 为类变量分配内存并且设置该类变量的默认初始值,即零值。

  • 这里不包含用final修饰的static,因为fina1在编译的时候就会分配了,准备阶段会显式初始化;

  • 这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中

2.3解折(Resolve)
  • 将常量池内的符号引用转换为直接引用的过程。

  • 解析操作往往会伴随着JVM在执行完初始化之后再执行。

  • 符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。

  • 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANT class info、CONSTANT Fieldref info、CONSTANT Methodref info等

3.初始化

  • 初始化阶段就是执行类构造器方法clinit的过程。

  • 此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。

  • 构造器方法中指令按语句在源文件中出现的顺序执行。

  • clinit()不同于类的构造器。(关联: 构造器是虚拟机视角下的clinit

  • 若该类具有父类,JM会保证子类的clinit() 执行前,父类的clinit(已经执行完毕。

  • 虚拟机必须保证一个类的clinit方法在多线程下被同步加锁
    在这里插入图片描述

二.类的加载器

4.作用

  • 类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识。

  • classLoader只负责class文件的加载,至于它是否可以运行,则由ExecutionEngine决定。

  • 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外,方法区中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)

在这里插入图片描述

5.分类

  • JVM支持两种类型的类加载器,分别为引导类加载器 (BootstrapclassLoader)和自定义类加载器[user-Defined ClassLoader)
  • 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象classLoader的类加载器都划分为自定义类加载器。
  • 无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3个,如下所示:

在这里插入图片描述

这里的四者之间的关系是包含关系。不是上层下层,也不是子父类的继承关系。

5.1启动类加载器(引导类加载器,Bootstrap ClassLoader)
  • 这个类加载使用C/C++语言实现的,嵌套在JVM内部。

  • 它用来加载Java的核心库 (JAVA HOME/re/lib/rt.jar、resources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类

  • 并不继承自java.lang.classLoader,没有父加载器

  • 加载扩展类和应用程序类加载器,并指定为他们的父类加载器

  • 出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类

5.2扩展类加载器(Extension ClassLoader)
  • Java语言编写,由sun.misc.LauncherSExtClassLoader实现
  • 派生于classLoader类
  • 父类加载器为启动类加载器
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的ire/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。
5.3应用程序类加载器(系统类加载,AppclassLoader)
  • java语言编写,由sun.misc.LauncherSAppClassLoader实现

  • 派生于classLoader类

  • 父类加载器为扩展类加载器

  • 它负责加载环境变量classpath或系统属性 java.class.path 指定路径下的类库

  • 该类加载是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载

  • 通过classLoader.getSystemClassLoader0)方法可以获取到该类加载器

5.4用户自定义类加载器

在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方
为什么要自定义类加载器?

  • 隔离加载类
  • 修改类加载的方式
  • 扩展加载源
  • 防止源码泄漏

用户自定义类加载器实现步骤:

1.开发人员可以通过继承抽象类java.lang.classLoader类的方式,实现自己的类加载器,以满足一些特殊的需求

2.在JDK1.2之前,在自定义类加载器时,总会去继承classLoader类并重写loadclass0)方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖loadclass()方法,而是建议把自定义的类加载逻辑写在findclass()方法中

3.在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URIClassLoader类,这样就可以避免自己去编写findclass()方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。

classLoader类,它是一个抽象类,其后所有的类加载器都继承自classLoader (不包括启动类加载器)

在这里插入图片描述

获取ClassLoader的途径

  • 方式一:获取当前类的ClassLoader
    clazz.getClassLoader()
  • 方式二:获取当前线程上下文的ClassLoader
    Thread.currentThread().getContextClassLoader()
  • 方式三:获取系统的ClassLoader
    ClassLoader.getSystemClassLoader()
  • 方式四:获取调用者的ClassLoader
    DriverManager.getCallerClassLoader

相关文章:

JVM类的加载和类的加载器

JVM类的加载和类的加载器 一.类的加载过程 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于…...

MLM:多模态大型语言模型的简介、微调方法、发展历史及其代表性模型、案例应用之详细攻略

MLM:多模态大型语言模型的简介、微调方法、发展历史及其代表性模型、案例应用之详细攻略 目录 相关文章 AI之MLM:《MM-LLMs: Recent Advances in MultiModal Large Language Models多模态大语言模型的最新进展》翻译与解读 MLM之CLIP:CLIP…...

Java健康养老智慧相伴养老护理小程序系统源码代办陪诊陪护更安心

健康养老,智慧相伴 —— 养老护理小程序,代办陪诊陪护更安心 🌈【开篇:智慧养老,新时代的温馨守护】🌈 在这个快节奏的时代,我们总希望能给予家人更多的关爱与陪伴,尤其是家中的长…...

Python | Leetcode Python题解之第390题消除游戏

题目&#xff1a; 题解&#xff1a; class Solution:def lastRemaining(self, n: int) -> int:a1 1k, cnt, step 0, n, 1while cnt > 1:if k % 2 0: # 正向a1 stepelse: # 反向if cnt % 2:a1 stepk 1cnt >> 1step << 1return a1...

Github 2024-09-01 开源项目月报 Top16

根据Github Trendings的统计,本月(2024-09-01统计)共有16个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目9TypeScript项目5Dart项目2C项目1Jupyter Notebook项目1Rust项目1开发者职业成长指南 创建周期:2670 天开发语言:TypeScript协议类…...

C++ 继承(二)

目录 1. 实现一个不能被继承的类 2. 友元与继承 3.继承与静态成员 4.多继承及其菱形继承问题 (1). 继承模型 (2). 虚继承 (2.1)虚继承解决数据冗余和二义性的原理 (3). 多继承中指针偏移问题 (4). IO库中的菱形虚拟继承 5. 继承和组合 1. 实现一个不能被继承的类 方法1…...

第 2 章:AJAX 的使用

AJAX 的使用 核心对象&#xff1a;XMLHttpRequest&#xff0c;AJAX 的所有操作都是通过该对象进行的。 1. 使用步骤 创建 XMLHttpRequest 对象 var xhr new XMLHttpRequest(); 设置请求信息 xhr.open(method, url);//可以设置请求头&#xff0c;一般不设置 xhr.setReques…...

ROS——视觉抓取

纲要 视觉抓取中的关键技术 内参标定 物体识别定位 抓取姿态分析 运动规划 外参标定 任意两个位姿之间的关系 眼在外 眼在内 手眼标定流程 robot 部分 标定效果 视觉抓取例程 grasping_demo.cpp 获取两个坐标系之间变换关系:waitForTransform 、 LookupTransform 求相…...

EPLAN2022基础教程

EPLAN2022软件介绍 EPLAN是一款专业的电气设计和绘图软件&#xff0c;它可以帮助我创建和管理电气项目&#xff0c;生成各种报表和文档&#xff0c;与其他软件和系统进行交互&#xff0c;优化工程流程和质量。与传统的CAD绘图对比&#xff0c;EPLAN更适合绘制电气原理图。 下…...

【JavaWeb】Servlet 详解(处理逻辑及常见方法)

文章目录 1. Tomcat1.1 常见的错误1.1.1 出现 4041.1.2 出现 4051.1.3 出现 500 1.2 HttpServlet1.2.1 Tomcat 的处理逻辑1.2.2 相关方法 1.3 HttpServletRequest1.3.1 常见方法1.3.2 jackson 处理逻辑 1.4 HttpServletResponse1.4.1 常见方法 1. Tomcat tomcat 是一个 HTTP 服…...

6 自研rgbd相机基于rk3566之深度计算库程序详解

自研rgbd相机基于rk3566之深度计算库详解 1 tof深度计算库框架读入深度图像参数配置tof模组标定参数读入及解析深度计算函数接口2 tof深度计算库程序详解深度计算程序头文件深度计算程序 源文件1 tof深度计算库框架 读入深度图像参数配置 支持raw8/raw10/raw16 格式 /*******…...

分布式系统框架hadoop3入门

分布式系统框架hadoop3入门 (qq.com) Hadoop3作为分布式系统架构的重要基石&#xff0c;为大规模数据存储与处理提供了强大支持 基本信息 hadoop&#xff1a;一个存储和处理大数据的分布式系统框架 组成&#xff1a; HDFS&#xff08;数据存储&#xff09;、MapReduce&…...

使用 i3.LayoutCell() 方法绘制版图并输出为 GDS 文件

使用 i3.LayoutCell 方法绘制版图并输出为 GDS 文件 引言正文引言 在 IPKISS i3.SRef() 函数 一文中我们介绍了如何使用 i3.SRef() 函数将 instance 对象添加到 i3.LayoutCell() 创建的 Cell 对象上。但是当我们使用 write_gdsii() 输出版图时代码就会报错。这里我们将介绍如何…...

mariadb容器

下载镜像 $ sudo docker pull mariadb启动容器 $ sudo docker run --name my-mariadb -d -e MARIADB_DATABASEtestdb -e MARIADB_ROOT_PASSWORDLetmein -p 3306:3306 mariadb上面命令会启动一个名为my-mariadb的容器&#xff0c;并初始化一个testdb数据库&#xff0c;同时设置…...

应用层协议Http

Http协议 1.1 什么是http协议 在进行网络通信时&#xff0c;应用层协议一般都是程序员自己写的&#xff0c;但是有一些大佬其实已经定义出了一些现成的应用层协议&#xff0c;例如&#xff1a;HTTP&#xff08;超文本传输协议&#xff09;、FTP&#xff08;文件传输协议&#…...

display flex 的div 被子元素撑开不显示滚动条的一个解决demo

display flex 的div 被子元素撑开&#xff0c;不显示y轴滚动条的 一个解决demo。 注&#xff1a; 不一定适用所有人的的相同问题 less # less .contact {display: flex;flex-grow: 1;overflow: hidden auto;flex-direction: column;.contact-items {flex: 1 1 0;display: flex…...

判断键盘输入是数字、大写字母还是小写字母——C#学习笔记

以下代码将判断键盘输入字符是数字 还是字母&#xff1a; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ConsoleApp4 {using System;using System.Threading;public class BoolKeyTest{sta…...

进程控制块PCB的组织方式有哪些?

进程控制块&#xff08;PCB&#xff0c;Process Control Block&#xff09;是操作系统用来管理和跟踪进程的一个数据结构&#xff0c;它保存了与进程相关的各种信息。PCB 是操作系统调度进程的核心数据结构&#xff0c;通常通过某种组织方式进行管理。常见的 PCB 组织方式主要有…...

getent passwd 获取linux并显示用户账户信息

getent passwd 命令在Unix和类Unix系统&#xff08;如Linux&#xff09;中用于从系统的密码数据库&#xff08;通常是/etc/passwd文件&#xff0c;但在某些配置中可能是通过网络服务如NIS或LDAP&#xff09;中获取并显示用户账户信息。这个命令的输出列出了系统上所有用户的详细…...

达梦数据库+JPA+Springboot 报错 :无效的列名

文章目录 0、 开发环境1、需求说明2、适配过程3、问题描述和解决3.1报错问题3.2 问题解决 0、 开发环境 开发环境&#xff1a; idea 2022 SpringBoot版本 &#xff1a;2.7.1 JDK 111、需求说明 适配国产化数据库达梦8 2、适配过程 参考 Springboot jpa 达梦 3、问题描述…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...