JVM—类的生命周期
目录
类的生命周期
加载阶段
连接阶段
验证阶段
准备阶段
解析阶段
初始化阶段
面试题1
面试题2
类的生命周期

类的生命周期描述了一个类加载、使用、卸载的整个过程,整体可以分为以下五个阶段。
1. 加载
2. 连接,其中又分为验证、准备、解析三个子阶段
3. 初始化
4. 使用
5. 卸载
加载阶段
一、加载阶段的第一步是类加载器通过不同的渠道,以二进制流的形式获取字节码信息,这些渠道可以通过程序员使用Java代码进行扩展,常见渠道如下。
1. 从本地磁盘上获取文件
2. 运行时通过动态代理生成,比如Spring框架
3. Applet技术通过网络获取字节码文件
二、类加载器加载类后,Java虚拟机会将字节码中的信息存储到方法区,并在方法区中生成一个 InstanceKlass 对象。这个对象保存了类的所有信息,包括实现多态等特定功能的信息。
三、Java虚拟机同时会在堆上生成与方法区中数据相似的 java.lang.Class 对象,其作用是在Java代码中获取类的信息并存储静态字段的数据(适用于JDK8及之后版本)。
堆中的对象仅包含方法区对象的部分信息。对开发者而言,只需访问堆中的 Class 对象,而无需接触方法区中的所有信息。这样,Java虚拟机可以有效控制开发者对数据的访问范围。
连接阶段

验证阶段
验证阶段的主要目的是检测Java字节码文件是否符合《Java虚拟机规范》的约束。该阶段通常无需程序员参与,主要包括以下四个部分,具体细节请参见《Java虚拟机规范》:
1. 文件格式验证:检查文件是否以0xCAFEBABE开头,以及主次版本号是否符合当前Java虚拟机版本的要求;
2. 元信息验证:确保类具有父类(即super不能为null);
3. 指令语义验证:检查程序执行指令的正确性,例如方法内指令是否跳转到合法的位置;
4. 符号引用验证:确认是否尝试访问其他类中的private方法等。
准备阶段
准备阶段负责为静态变量(static)分配内存并设置初始值。在这一阶段,每种基本数据类型和引用数据类型都有其特定的默认值。而在初始化阶段,静态变量的值才会被更新为代码中指定的值。需要注意的是,对于被 final 修饰的基本数据类型静态变量,准备阶段会直接将其赋予代码中指定的值。这一阶段的重要性在于,它确保所有静态变量在类加载时都有一个一致的状态,为后续的初始化提供基础。
解析阶段
解析阶段的主要任务是将常量池中的符号引用替换为直接引用。在字节码文件中,符号引用通过编号访问常量池的内容,而直接引用则使用内存地址进行访问。这一转换提高了访问效率,减少了查找开销,使得Java虚拟机能够更快速地定位和使用数据。
初始化阶段
初始化阶段会执行字节码文件中clinit(class init 类的初始化)方法的字节码指令,包含了静态代码块中的代码,并为静态变量赋值。
public class Demo1 {public static int value = 1;static {value = 2;}public static void main(String[] args) {}
}
以上代码编译成字节码文件之后,会生成以下三个方法:
1、init方法:会在对象初始化时执行
2、main方法:主方法
3、clinit方法:类的初始化阶段执行
接下来分析clinit方法中的字节码指令
1、iconst_1,将常量1放入操作数栈。此时栈中只有1这个数;
2、putstatic指令会将操作数栈上的数弹出来,并放入堆中静态变量的位置,字节码指令中#2指向了常量池中的静态变量value,在解析阶段会被替换成变量的地址;
3、前面两步操作相当于执行value=1;后面两步操作同理,执行value=2,将堆上的value赋值为2。
public class Demo1 {static {value = 2;}public static int value = 1;public static void main(String[] args) {}
}/* 原代码顺序public static int value = 1;static {value = 2;}
*/
如果将代码的位置互换,字节码指令的位置也会发生变化,如下图。 这样初始化结束之后,最终value的值就变成了1而不是2。
引起clinit执行的几种情况
1. 访问类的静态变量或静态方法;
注意:如果变量被 final 修饰且等号右侧的值是常量,则不会触发初始化。
2. 调用 Class.forName(String className) 时;
3. 创建该类的对象(使用 new 关键字);
4. 执行该类的 main 方法时。
Tip:添加-XX:+TraceClassLoading 参数可以打印出加载并初始化的类
clinit不会执行的几种情况
1.无静态代码块且无静态变量赋值语句;
2.有静态变量的声明,但是没有赋值语句;(如:public static int a;)
3.静态变量的定义使用final关键字,这类变量会在准备阶段直接进行初始化;
(如:public final static int a= 10;)
4.数组的创建不会导致数组中元素的类进行初始化。
面试题1
public class Test1 {public static void main(String[] args) {System.out.println("A");new Test1();new Test1();}public Test1(){System.out.println("B");}{System.out.println("C");}static {System.out.println("D");}
}
以上代码的输出结果是什么?
1、执行main方法之前,会先执行该类的clinit方法。clinit方法中执行了静态代码块中的方法,因此输出D;
2、之后走main方法,输出A;
3、随后创建两个对象,原则上会执行两次对象初始化的指令,但该对象在第一步时已经被加载并初始化,所以此处不再加载与初始化,而是走构造方法;
4、构造代码块优先于构造方法执行,因此先输出C,再输出B;创建两个对象,因此输出CBCB;
5、所以代码输出的结果为DACBCB
面试题2
public class Demo01 {public static void main(String[] args) {new B02();System.out.println(B02.a);}
}class A02{static int a = 0;static {a = 1;}
}class B02 extends A02{static {a = 2;}
}
以上代码的输出结果是什么?
1、调用new创建对象,需要初始化B02,有父类的情况优先初始化父类;
2、执行A02的初始化代码,最终将a赋值为1;
3、父类初始完成,进行本类B02初始化,将a赋值为2;
4、最终输出2。
变形
如果将new B02();注释掉会怎么样?
分析步骤:
1、访问父类的静态变量,只初始化父类,不初始本类;
2、执行A02的初始化代码,将a赋值为1;
3、最终输出1。
总结
1、直接访问父类的静态变量,不会触发子类的初始化。
2、子类的初始化clinit调用之前,会先调用父类的clinit初始化方法
相关文章:
JVM—类的生命周期
目录 类的生命周期 加载阶段 连接阶段 验证阶段 准备阶段 解析阶段 初始化阶段 面试题1 面试题2 类的生命周期 类的生命周期描述了一个类加载、使用、卸载的整个过程,整体可以分为以下五个阶段。 1. 加载 2. 连接,其中又分为验证、准备、解析三…...
SELinux中的安全标记与强制访问控制
SELinux的安全标记和强制访问控制是如何实现的? SELinux(Security Enhanced Linux)是一个由美国国家安全局(NSA)开发的Linux内核模块,它实现了强制访问控制(MAC)。SELinux通过为系统…...
EasyExcel_动态表头的导入导出
文章目录 前言一、EasyExcel二、使用步骤1.引入jar包2.数据准备2.1 数据库 3.方法实例3.1 无实体的导入3.1.1 Controller3.1.2 Service3.1.3 Listener3.1.4 Utils3.1.5 无实体导入数据返回说明 3.2 无实体的导出3.2.1 无实体导出数据(这里只贴出关键代码,Service代码处理)3.2.2…...
uni-app简单模拟人脸识别
uni-app使用live-pusher简单模拟人脸识别页面样式 实现想法调起手机摄像头设置圆形 实现想法 公司的需求是模拟一个人脸识别,不用第三发插件,简单模拟样式即可。 基本思路是调起手机前置摄像头,再设置一个圆形的样式来达到一个基本样式 调起…...
华为HCIE-OpenEuler认证详解
华为HCIE认证(Huawei Certified ICT Expert)是华为提供的最高级别的专业认证,它旨在培养和认证在特定技术领域具有深厚理论知识和丰富实践经验的专家级工程师。对于华为欧拉(OpenEuler)方向的HCIE认证,即HC…...
从零开始的Go语言之旅(2 Go by Example: Values)
Go 语言有多种值类型,包括字符串、整数、浮点数、布尔值等。以下是一些基本示例。 package mainimport "fmt"func main() {fmt.Println("go" "lang")fmt.Println("11 ", 11)fmt.Println("7.0/3.0 ", 7.0/3.0)f…...
XShell 中实现免密登录 Linux 服务器的详细流程
个人主页:Jason_from_China-CSDN博客 所属栏目:Linux系统性学习_Jason_from_China的博客-CSDN博客 所属栏目:Linux知识点的补充_Jason_from_China的博客-CSDN博客 XShell 中实现免密登录 Linux 服务器的详细流程: 一、在本地生成…...
跨界创新|使用自定义YOLOv11和Ollama(Llama 3)增强OCR文本识别
《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…...
一些关于 WinCC Comfort 和 WinCC Advanced 脚本编程语言 VBS 的实用技巧
为什么一个由内部变量的 “数值更变” 事件触发的脚本不执行? 如果使用一个内部变量调用另外一个内部变量,以此,例如被调用的变量又去执行一个脚本(比如,根据变量变化),此时一个安全机制会阻止这…...
Java|乐观锁和悲观锁在自旋的时候分别有什么表现?
乐观锁和悲观锁是两种不同的并发控制策略,各自采用不同的机制来处理线程之间的资源竞争。 乐观锁 1. 定义 乐观锁是一种假设冲突不会发生的并发控制策略,通常不对资源进行加锁,而是在操作前不加锁,操作后再进行验证。乐观锁通常…...
Linux定时器定时任务清理log日志文件
首先,创建xx.sh文件,内容如下 #!/bin/bash sfecho "" > /var/lib/docker/containers/12379e809ea1294eea9b117368181cff1dd3915fdb1611f940c5cf3d6077d734/12379e809ea1294eea9b117368181cff1dd3915fdb1611f940c5cf3d6077d734-json.log 打…...
美国大学生数学建模竞赛(MCM/ICM)介绍
美国大学生数学建模竞赛(MCM/ICM)是一项具有较高影响力的国际赛事。以下是一份美赛教程: 一、前期准备 组队 寻找合适的队友,最好具备不同的专业技能,如数学、计算机、工程等。团队成员应具备良好的沟通能力、合作精神和责任心。明确各自的分工,例如有人负责建模、有人负…...
【独家:AI编程助手Cursor如何revolutionize Java设计模式学习】
【独家:AI编程助手Cursor如何revolutionize Java设计模式学习】 导语 在Java高级编程的世界里,设计模式是每个开发者必须掌握的利器。但是,如何快速理解并灵活运用这些模式呢?让我们一起探索如何借助AI编程助手Cursor,轻松掌握设计模式,提升Java编程技能! 正文 设计模式:J…...
数据仓库宽表概述
宽表是指一种将多个相关数据集整合到一个表中的数据建模方法,具有减少连接操作、提高查询性能、简化数据管理的优点。 一、宽表的定义 宽表,顾名思义,是一种在数据仓库中使用的表格形式,其特征是包含了大量的列。这种表格设计的…...
在数据库中编程 vs 在应用程序中编程
原文地址 https://brandur.org/fragments/code-database-vs-app 数据库领域有一个长期存在的问题:你是更愿意将应用逻辑放在更接近数据库本身的存储过程和触发器中,还是置于数据库之上的应用程序代码中? 没有客观正确的答案,只有…...
【设计模式系列】装饰器模式
目录 一、什么是装饰器模式 二、装饰器模式中的角色 三、装饰器模式的典型应用场景 四、装饰器模式在BufferedReader中的应用 一、什么是装饰器模式 装饰器模式是一种结构型设计模式,用于在不修改对象自身的基础上,通过创建一个或多个装饰类来给对象…...
你真的知道TCP协议中的序列号确认、上层协议及记录标识问题吗?
引言 在前面的内容中,我们已经详细讲解了一系列与TCP相关的面试问题。然而,这些问题都是基于个别知识点进行扩展的。今天,我们将重点讨论一些场景问题,并探讨如何解决这些问题。 序列号确认问题 当A主机与B主机建立了TCP连接后…...
一家生物技术企业终止,科创属性可能不足,报告期内专利数猛增
轩凯生物九成以上营业收入来源于植物营养领域,收入来源结构单一,产品下游应用领域较为集中。报告期内公司应收账款账面价值逐年上升,回款比例显著低于前两年,遭交易所问询是否存在较大的坏账风险。 轩凯生物核心技术是否成熟以及是…...
使用 Python 的 BeautifulSoup(bs4)解析复杂 HTML
使用 Python 的 BeautifulSoup(bs4)解析复杂 HTML:详解与示例 在 Web 开发和数据分析中,解析 HTML 是一个常见的任务,尤其是当你需要从网页中提取数据时。Python 提供了多个库来处理 HTML,其中最受欢迎的就…...
Spring Cache Caffeine 高性能缓存库
Caffeine 背景 Caffeine是一个高性能的Java缓存库,它基于Guava Cache进行了增强,提供了更加出色的缓存体验。Caffeine的主要特点包括: 高性能:Caffeine使用了Java 8最新的StampedLock乐观锁技术,极大地提高了缓存…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
