快速理解类的加载过程
当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过如下三个步骤来对该类进行初始化:
1.加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象;
2.链接:Java类的二进制代码合并到JVM的运行状态之中的过程。
(1)验证:确保加载的类信息符合JVM规范,没有安全方面的问题;
(2)准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配;(static是在内初始化之前就完成了)
(3)解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。()
3.初始化:
(1)执行类构造器<clinit>()方法的过程:类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的(类构造器是构造类信息的,不是构造该类对象的构造器);(JVM去完成的)
(2)当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化;
(3)虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。
总结:
虚拟机把Class文件加载到内存,并对数据进行校验、转换解析和初始化,形成可以虚拟机直接使用的Java类型,即java.lang.Class,如下图:
接下来会对该三个步骤逐一进行解释。
一.类的加载
作用:查找和导入Class文件。
步骤:
1.通过一个类的全限定名获取定义此类的二进制字节流;(那么这个时候需要一个寻找器,来寻找获取我们的二进制字节流,而java中恰好有这么一段代码模块,可以实现通过类全名来获取此类的二进制字节流这个动作,并且将这个动作放到放到java虚拟机外部去实现,以便让应用程序决定如何获取所需要的类,实现这个动作的代码模块成为“类加载器”)
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
3.在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口。(此时静态数据结构已经放进了方法区,但是此时我们没有办法去进行访问,java当中去访问数据的方法是通过引用去操作对象,然后通过对象去操作数据,所以还需要再堆当中去生成一个代表代表这个类的java.lang.Class对象,作为方法区中的数据访问入口)
在加载阶段完成之后,这个时候在内存当中,运行时数据区的方法区以及堆就已经有数据了:
(1)方法区:类信息,静态变量,常量;
(2)堆:代表被加载类的java.lang.Class对象。
及时编译之后的热点代码并不在这个阶段进入方法区。
类加载器:
类加载器作用是用来把类(class)装载进内存的,JVM 规范定义了如下类型的类的加载器:
二.类的链接
1.验证
作用:
验证只要是为了确保Class文件中的字节流包含的信息完全符合当前虚拟机的要求,并且还要求我们的信息不会危害虚拟机自身的安全,导致虚拟机的崩溃。
验证内容:
文件格式的验证、元数据验证、字节码的验证、符号引用的验证。
2.准备
作用:
为类的静态变量分配内存,并且初始化为当前类型的默认值。
解释:
1.这里不包含用final修饰的static,因为final在编译的时候就会分配了,准备阶段会显式初始化,这里不会为实例变量(也就是没加static)分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中;
2.进行分配内存的只是包括类变量(静态变量),而不包括实例变量,实例变量是在对象实例化时随着对象一起分配在java堆中的,通常情况下,初始值为零值,假设public static int a=1,那么a在准备阶段过后的初始值为0,不为1,这时候只是开辟了内存空间,并没有运行java代码,a赋值为1的指令是程序被编译后,存放于类构造器()方法之中,所以a被赋值为1是在初始化阶段才会执行。
3.解析
作用:
把类中的符号引用转换为直接引用:
(1)符号引用就是一组符号来描述目标,可以是任何字面量;
(2)直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
(因为再一个Class文件中,没有办法去表示引用关系,只能告诉你引用到10行或者20行这种,直接应用就表示你执行的位置在内存当中有一块具体的地址,比如说a指向b是符号应用,a指向b所在的位置0x01,在内存中这叫直接引用)
解释:
(1)解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行;
(2)直接应用是与虚拟机内存布局相关的,同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般是不相同的,如果有了直接引用,那引用的目标必定存在内存中;
(3)类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过VM垃圾回收机制可以回收这些Class对象。(同一符号引用进行多次解析请求是很常见的,除invokedynanic指令以外,虚拟机实现可以对第一次解析结果进行缓存,来避免解析动作重复进行,无论是否真正执行了多解析动作,虚拟机需要保证的是在同一个实体中,如果一个引用符号之前已经被成功解析过,那么后续的引用能析请求就应当一直成功,同样的,如果第一次解析失败,那么其他指令对这个符号的解析请求也应该收到相同的异常)
(4)inDy(invokedynamic)是java7引入的一条新的虚拟机指令,这是自 1.0 以来第一次引入新的虚拟机指令,到了 java 8 这条指令才第一次在java 应用,用在 lambda 表达式中,indy 与其他 invoke 指令不同的是它允许由应用级的代码来决定方法解析。
三.类的初始化
作用:
初始化阶段是执行类构造器Clinit()方法的过程,或者讲得通俗易懂些,加载和链接以外的工作都需要在初始化中去完成。
在准备阶段,类变量已赋过一次系统要求的初始值,而在初始化阶段,则是根据自己通过程序制定的主观计划去初始化变量和其他资源,比如赋值。
什么时候发生类初始化:
1.类的主动引用(一定会发生类的初始化):
(1)当虚拟机启动,先初始化main方法所在的类;
(2)new一个类的对象;
(3)调用类的静态成员(除了final常量)和静态方法;
(4)使用java.lang.reflect包的方法对类进行反射调用;
(5)当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类;
2.类的被动引用(不会发生类的初始化):
(1)当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量不会导致子类初始化;
(2)通过数组定义类引用,不会触发此类的初始化;
(3)引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)。
在Java中对类变量进行初始值设定有两种方式:
1.声明类变量是指定初始值;
2.使用静态代码块为类变量指定初始值。
按照程序逻辑,必须把静态变量定义在静态代码块的前面,因为两个的执行是会根据代码编写的顺序来决定的,顺序搞错了可能会影响你的业务代码。
JVM初始化步骤:
1.假如这个类还没有被加载和连接,则程序先加载并链接该类;
2.假如该类的直接父类还没有被初始化,则先初始化其直接父类;
3.假如类中有初始化语句,则系统依次执行这些初始化语句。
四.举例
代码如下:
public class Test {public static void main(String[] args) {A a = new A();System.out.println(A.m);/*1.加载到内存 ,会产生一个类对应class对象2.链接 ,链接结束后 m = 03.初始化 m= 100:<clinit>(){System.out.println("A类静态代码块初始化”);m = 300;m=100}*/}
}class A {static {System.out.println("A类静态代码块初始化");m = 300;}static int m = 100;public A() {System.out.println("A类的无参构造初始化");}
}
输出结果:
A类静态代码块初始化
A类的无参构造初始化
100
大概流程如下:
首先在方法区产生了一些该类的静态数据,然后在加载的类的时候,就产生了对应的class,然后看main()方法,main()方法后就开始链接,此时m有一个初始值0,等链接完没有问题的时候,就开始执行代码,此时new A(),就产生了一个A类的对象,这个对象就会去找到自己的Class类(指向),通过A类的数据结构,给A类对象赋值(拿到数据),赋值完成后,通过clinit()方法初始化数据,得到m等于100。
相关文章:

快速理解类的加载过程
当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过如下三个步骤来对该类进行初始化: 1.加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个…...

医院跌倒检测识别 使用YOLO,COCO ,VOC格式对4806张原始图片进行标注,可识别病人跌倒,病人的危险行为,病床等场景,预测准确率可达96.7%
医院跌倒检测识别 使用YOLO,COCO ,VOC格式对4806张原始图片进行标注,可识别病人跌倒,病人的危险行为,病床等场景,预测准确率可达96.7% 数据集分割 4806总图像数 训练组70% 3364图片 有效集20&#…...
[Unity Shader] 【游戏开发】【图形渲染】Unity Shader的种类2-顶点/片元着色器与固定函数着色器的选择与应用
Unity 提供了不同种类的 Shader,每种 Shader 有其独特的优势和适用场景。在所有类型的 Shader 中,顶点/片元着色器(Vertex/Fragment Shader)与固定函数着色器(Fixed Function Shader)是两种重要的着色器类型。尽管它们具有不同的编写方式和用途,理解其差异与应用场景,对…...
浏览器端的 js 包括哪几个部分
一、核心语言部分 1. 变量与数据类型 变量用于存储数据,在 JavaScript 中有多种数据类型,如基本数据类型(字符串、数字、布尔值、undefined、null)和引用数据类型(对象、数组、函数)。 let name "…...

GoogLeNet网络:深度学习领域的创新之作
目录 编辑 引言 GoogLeNet的核心创新:Inception模块 Inception模块的工作原理 1x1卷积:降维与减少计算量 1x1卷积的优势 深度分离卷积:计算效率的提升 深度分离卷积的实现 全局平均池化:简化网络结构 全局平均池化的作…...

深入C语言文件操作:从库函数到系统调用
引言 文件操作是编程中不可或缺的一部分,尤其在C语言中,文件操作不仅是处理数据的基本手段,也是连接程序与外部世界的重要桥梁。C语言提供了丰富的库函数来处理文件,如 fopen、fclose、fread、fwrite 等。然而,这些库…...
Java序列化
Java序列化 简单来说: 序列化是将对象的状态信息转换为可以存储或传输的形式(如字节序列)的过程。在 Java 中,通过序列化可以把一个对象保存到文件、通过网络传输到其他地方或者存储到数据库等。最直接的原因就是某些场景下需要…...

基坑表面位移沉降倾斜自动化监测 非接触式一体化解决机器视觉
基于变焦视觉位移监测仪的基坑自动化监测新方案是一种集成了光学、机械、电子、边缘计算、AI识别以及云平台软件等技术的自动化系统。该方案利用变焦机器视觉原理,结合特殊波段成像识别技术和无源靶标,实现了非接触式大空间、多断面、多测点的高精度水平…...
提升效率:精通Windows命令行的艺术
文章目录 引言1. 基本目录操作命令dir:列出目录内容cd:更改目录mkdir 和 rmdir:创建和删除目录 2. 文件操作命令copy:复制文件或目录move:移动或重命名文件/目录del:删除文件 3. 文件查看命令typeÿ…...

ESP32-S3-devKitC-1 点亮板上的WS2812 RGB LED
ESP32-S3-devKitC-1 板上自带了一个RGB LED,型号为 WS2812。 RGB LED 在板上的位置如下图所示。 为了点亮这个WS2812,需要确定这颗RGB LED连接到哪个GPIO上了。 下面是确定GPIO管脚的过程: 1、根据原理图 2、根据PCB布局图: 程…...

python调用matlab函数(内置 + 自定义) —— 安装matlab.engine
文章目录 一、简介二、安装matlab.engine2.1、基于 CMD 安装2.2、基于 MATLAB 安装(不建议) 三、python调用matlab函数(内置 自定义) 一、简介 matlab.engine(MATLAB Engine API for Python):…...

CAD c# 生成略缩图预览
代码如下: using (Transaction tr currentdb.TransactionManager.StartTransaction()){//当前数据库开启事务using (Database tempdb new Database(false, true)) //创建临时数据库(两个参数:是否创建符号表,不与当前文档关联){try{Bitmap …...

端点鉴别、安全电子邮件、TLS
文章目录 端点鉴别鉴别协议ap 1.0——发送者直接发送一个报文表明身份鉴别协议ap 2.0——ap1.0 的基础上,接收者对报文的来源IP地址进行鉴别鉴别协议ap 3.0——使用秘密口令,口令为鉴别者和被鉴别者之间共享的秘密鉴别协议ap 3.1——对秘密口令进行加密&…...

汽车电子元件的可靠性保障:AEC-Q102认证
AEC-Q102标准的起源与价值 随着汽车电子系统的日益复杂,电子器件必须能够在极端的温度、湿度、振动和电磁干扰等恶劣条件下保持性能。AEC-Q102标准由汽车电子委员会(AEC)制定,专门针对LED、激光二极管和光电二极管等光电器件&…...

主成分分析法大全(包括stata+matlab)
数据简介:主成分分析(Principal Component Analysis,PCA), 是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。在实际课题中,为了…...

ubuntu+ros新手笔记(五):初探anaconda+cuda+pytorch
深度学习三件套:初探anacondacudapytorch 系统ubuntu22.04 1.初探anaconda 1.1 安装 安装过程参照【详细】Ubuntu 下安装 Anaconda 1.2 创建和删除环境 创建新环境 conda create -n your_env_name pythonx.x比如我创建了一个名为“py312“的环境 conda cre…...
C++ List(双向链表)
是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个 信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定 的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中&#…...

ASP.NET|日常开发中读写TXT文本详解
ASP.NET|日常开发中读写TXT文本详解 前言一、读取 TXT 文本1.1 使用StreamReader类 二、写入 TXT 文本2.1 使用StreamWriter类 三、文件编码问题3.1 常见编码格式 四、错误处理和性能考虑4.1 错误处理4.2 性能考虑 结束语优质源码分享 ASP.NET|日常开发中…...

【机器学习】在不确定的光影中:机器学习与概率论的心灵共舞
文章目录 概率与统计基础:解锁机器学习的数据洞察之门前言一、概率论基础1.1 概率的基本概念与性质1.1.1 概率的定义1.1.2 样本空间与事件1.1.3 互斥事件与独立事件1.1.4 概率的计算方法 1.2 条件概率与独立性1.2.1 条件概率1.2.2 独立事件 1.3 随机变量1.3.1 随机变…...

【论文笔记】Editing Models with Task Arithmetic
🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Editing Models with Task…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...