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

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乐观锁技术,极大地提高了缓存…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

<6>-MySQL表的增删查改

目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表&#xf…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

条件运算符

C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...