【JAVA】类加载过程,以及类加载器

news/2024/5/20 20:01:17

类加载过程,以及类加载器

    • 一、类加载的过程
    • 二、类加载器介绍
    • 三、跨类加载
    • 三、举例说明

一、类加载的过程

类加载是Java虚拟机(JVM)将类文件加载到内存中并转换成对应的类对象的过程。它确保了类文件能够正确加载并转换成可执行的类对象,为程序的执行提供了必要的基础设施。类加载过程主要包括以下几个步骤:
在这里插入图片描述

  • 加载(Loading):加载是指将类的字节码文件(.class文件)从磁盘或者网络中读取到内存中的过程。类加载器根据类的全限定名(Fully Qualified Name)来定位和加载类文件。加载过程不包括对类文件的解析和验证,仅仅是将字节码加载到内存中形成类对象的初始状态。
  • 验证(Verification):验证是指对加载的类文件进行字节码验证、符号引用验证等过程,确保类文件的格式和内容符合Java虚拟机规范,防止恶意代码或者不规范的代码对系统造成安全漏洞或者错误。
  • 准备(Preparation):准备是指为类的静态变量分配内存空间,并设置默认初始值的过程。在准备阶段,静态变量会被初始化为默认值,例如整数类型的默认值是0,引用类型的默认值是null。
  • 解析(Resolution):解析是指将类中的符号引用转换为直接引用的过程。在Java中,类的方法调用、字段访问等操作都是通过符号引用来实现的,解析阶段将这些符号引用转换为实际内存地址,使得程序可以直接访问类的方法和字段。
  • 初始化(Initialization):初始化是指执行类的初始化代码(静态代码块和静态变量赋值语句)的过程。在初始化阶段,JVM会按照类加载的先后顺序依次执行静态代码块和静态变量赋值语句,完成类的初始化工作。

需要注意的是,类加载过程是按需进行的,并不是一次性加载所有类文件。当程序需要使用某个类时,类加载器会先加载该类及其所依赖的类,然后进行验证、准备、解析和初始化操作。类加载器会按照委派模型逐级向上委托加载类,直到找到合适的类加载器为止。

对于已经加载的类会被放在 ClassLoader 中。在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。也就是说,对于一个类加载器来说,相同二进制名称的类只会被加载一次。
在这里插入图片描述

下面这个截图是ClassLoader类,里面有一个Vector变量用来存由这个类加载器加载的类。
在这里插入图片描述

二、类加载器介绍

具体来说,Java虚拟机中的类加载器主要分为以下几种:

  • 启动类加载器(Bootstrap Class Loader):负责加载Java的核心类库,例如java.lang.Object等。
  • 扩展类加载器(Extension Class Loader):负责加载Java的扩展类库,例如java.lang.String等。
  • 应用程序类加载器(Application Class Loader):也称为系统类加载器,负责加载应用程序的类,例如项目中自定义的类。
  • 自定义类加载器:开发者可以根据需要编写自定义的类加载器,用于加载特定的类或者资源。

三、跨类加载

跨类加载器指的是在Java虚拟机(JVM)中存在多个类加载器,这些类加载器可能会加载同一个类,导致在内存中存在多个版本的类实例。这种情况下,如果涉及到静态变量,可能会出现静态变量在不同类加载器加载的类中存在多份实例的情况

当存在多个类加载器时,如果不同的类加载器加载了同一个类,就会出现类实例的多个版本。对于静态变量,它们属于类级别的变量,在类加载时被初始化,因此不同类加载器加载的同一个类中的静态变量会有不同的实例。

这种情况下,如果静态变量被跨类加载器共享,可能会导致数据不一致的问题。因此,在设计应用程序时,需要考虑到类加载器的影响,合理使用静态变量,避免跨类加载器共享静态变量可能带来的问题。

三、举例说明

假设有一个简单的Java应用程序,其中包含一个类 MyClass,以及一个静态变量myStaticVariable,同时存在两个不同的类加载器A和B。

public class MyClass {public static int myStaticVariable = 0;public static void main(String[] args) {MyClass.myStaticVariable = 10;System.out.println("静态变量值:" + MyClass.myStaticVariable);}
}

现在,我们假设类加载器A加载了MyClass 类,而类加载器B也加载了同一个 MyClass 类。由于静态变量属于类级别的变量,因此每个类加载器都会为静态变量myStaticVariable分别创建一个实例。

假设在类加载器A中的MyClass类中修改了静态变量的值:

public class MyClass {public static int myStaticVariable = 0;static {myStaticVariable = 20;}public static void main(String[] args) {System.out.println("静态变量值:" + MyClass.myStaticVariable);}
}

而在类加载器B中的MyClass类中没有修改静态变量的值:

public class MyClass {public static int myStaticVariable = 0;public static void main(String[] args) {System.out.println("静态变量值:" + MyClass.myStaticVariable);}
}

那么,当在不同的类加载器中运行这两个版本的MyClass类时,会得到不同的输出结果:

在类加载器A中运行时,输出结果为"静态变量值:20",因为在类加载时,静态代码块将静态变量myStaticVariable的值设置为20。
在类加载器B中运行时,输出结果为"静态变量值:0",因为没有修改静态变量的值,保持默认值0。
这种情况下,就展示了静态变量在跨类加载器情况下可能出现的多份实例的情况。


http://www.mrgr.cn/p/84228141

相关文章

【半个月我拿下了软考证】软件设计师高频考点--系统化教学-网络安全

👨‍💻 收录于专栏:软件设计师考点暴击 ⭐🅰️进入狂砍分⭐ ⭐软件设计师高频考点文档, ⭐软件设计师高频考点专栏 ⭐软件设计师高频考点⭐ 🎶(A) 考点1,网络攻击 理解记忆 &#…

初学python记录:力扣1652. 拆炸弹

题目: 你有一个炸弹需要拆除,时间紧迫!你的情报员会给你一个长度为 n 的 循环 数组 code 以及一个密钥 k 。 为了获得正确的密码,你需要替换掉每一个数字。所有数字会 同时 被替换。 如果 k > 0 ,将第 i 个数字用…

【数据库原理及应用】期末复习汇总高校期末真题试卷06

试卷 一、选择题 1. ________是长期存储在计算机内的有组织,可共享的数据集合. A.数据库管理系统 B.数据库系统 C.数据库 D.文件组织 1. 有12个实体类型,并且它们之间存在15个不同的二元联系,其中4个是1:1联系类型,5…

pgsql查看指定模式的存储过程

pgsql查看指定模式的存储过程 在 PostgreSQL 中,如果你想要查看指定模式的存储过程(也称为函数),你可以使用 \df 或 \df 命令在 psql 命令行工具中,或者使用 SQL 查询来从 pg_catalog 系统模式中查询。 \df命令行查询…

基于Python的LSTM网络实现单特征预测回归任务(TensorFlow)

单特征:数据集中只包含2列,时间列价格列,仅利用价格来预测价格 目录 一、数据集 二、任务目标 三、代码实现 1、从本地路径中读取数据文件 2、数据归一化 3、创建配置类,将LSTM的各个超参数声明为变量,便于后续…

如何让加快OpenHarmony编译速度?

OpenHarmony 有两种编译方式,一种是通过 hb 工具编译,一种是通过 build.sh 脚本编译。本文笔者将提升 build.sh 方式编译速度的方法整理如下: 因为笔者只用 build.sh 脚本编译,没用过 hb 工具,好像下面的选项也可以用于…

容灾演练双月报|郑大一附院数据级容灾演练切换

了解更多灾备行业动态 守护数字化时代业务连续 目录 CONTENTS 01 灾备法规政策 02 热点安全事件 03 容灾演练典型案例 01 灾备法规政策 3月19日,工信部发布《工业和信息化部办公厅关于做好2024年信息通信业安全生产和网络运行安全工作的通知》。明确提出“…

llama.cpp制作GGUF文件及使用

llama.cpp的介绍 llama.cpp是一个开源项目,由Georgi Gerganov开发,旨在提供一个高性能的推理工具,专为在各种硬件平台上运行大型语言模型(LLMs)而设计。这个项目的重点在于优化推理过程中的性能问题,特别是…

我们的小程序每天早上都白屏,真相是。。。

大家好,我是程序员鱼皮。最近我们在内测一款面试刷题小程序,没错,就是之前倒下的 “面试鸭”! 在我们的内测交流群中,每天早上都会有同学反馈:打开小程序空白,没任何内容且登录不上。 然后过了…

开源离线AI笔记应用

前言 Reor 是一款人工智能驱动的桌面笔记应用程序,它能自动链接相关笔记、回答笔记中的问题并提供语义搜索。所有内容都存储在本地,支持 Windows、Linux 和 MacOS。Reor 站在 Ollama、Transformers.js 和 LanceDB 等巨头的肩膀上,使 LLM 和嵌…

iceoryx源码阅读(二)——共享内存管理

目录1 共享内存模型2 获取共享内存2.1 MemoryManager::getChunk2.2 MemPool::getChunk3 释放共享内存3.1 SharedChunk::freeChunk3.2 MemPool::freeChunk4 总结 基于共享内存通信的核心在于共享内存的管理,包括共享内存的分配、释放。 1 共享内存模型 iceoryx先将整块共享内存…

iceoryx源码阅读(一)——全局概览

一、什么是iceoryx iceoryx是一套基于共享内存实现的进程间通信组件。 二、源码结构 iceoryx源码包括若干工程,整理如下表所示:下图展示了主要项目之间的依赖(FROM:iceoryx(冰羚)-Architecture):三、iceoryx应用程序结构 iceoryx应用程序有三类进程,分别为Publisher、Su…

Linux字符设备驱动(一) - 框架

字符设备是Linux三大设备之一(另外两种是块设备,网络设备),字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,常见的字符设备包括鼠标、键盘、显示器、串口等等,当我们执行ls -l /dev的时候,就能看到大量…

1.4 初探JdbcTemplate操作

实战目的 掌握Spring框架中JdbcTemplate的使用,实现对数据库的基本操作。理解数据库连接池的工作原理及其在实际开发中的重要性。通过实际操作,加深对Spring框架中ORM(对象关系映射)的理解。 关键技术点 JdbcTemplate操作&…

重发布和路由策略

重发布 在同一个网络拓扑结构中,如果存在多种不同的路由协议,由于不同路由协议的机理各有不同,对路由的处理也不相同,这就在网络中造成了路由信息的隔离,在路由协议的边界设备上,将某种路由协议的路由信息引…

Java中的线程

一、创建线程的几种方式? ① 通过继承Thread类并重写run方法 ,实现简单但不可以继承其他类 Thread底层也是实现了Runnable接口,重写的是run而不是start方法 ②实现Runnable接口并重写run方法, 避免了单继承的局限性&#xff…

PVE安装Windows 95报错 while initializing device IOS

安装Win95重启后报错信息如下图,重启一直报错 while initializing device IOS,查了下报错原因说是 CPU频率太高导致,需要安装AMDK6UPD.EXE补丁包 下载地址 https://zhangka.lanzouw.com/igW0S1y8p5pe 打补丁操作流程: 1)将下载的iso文件加载到新光盘中 2)重启到dos环境…

迅饶科技 X2Modbus 网关 AddUser 任意用户添加漏洞复现

0x01 产品简介 X2Modbus是上海迅饶自动化科技有限公司Q开发的一款功能很强大的协议转换网关, 这里的X代表各家不同的通信协议, 2是T0的谐音表示转换, Modbus就是最终支持的标准协议是Modbus协议。用户可以根据现场设备的通信协议进行配置,转成标准的Modbus协议。在PC端仿真…

# IDEA 复制项目 Module 出现 不同模块下的 Product 类报错

IDEA 复制项目 Module 出现 不同模块下的 Product 类报错 我们 用 IDEA 复制项目 Module 出现 不同模块下的 Product 类报错,发现复制的 module 名称没有改变或者 java 文件夹后面还有原项目 source root 字样,maven 父子项目没有标识等问题。 解决方法…

【前端】实现表格简单操作

简言 表格合并基础篇 本篇是在上一章的基础上实现,实现了的功能有添加行、删除行、逆向选区、取消合并功能。 功能实现 添加行 添加行分为在上面添加和在下面追加行。 利用 insertAdjacentElement 方法实现,该方法可以实现从前插入元素和从后插入元…