JVM工作原理与实战(七):类的生命周期-初始化阶段

专栏导航

JVM工作原理与实战

RabbitMQ入门指南

从零开始了解大数据


目录

专栏导航

前言

一、类的生命周期

1.加载(Loading)

2.连接(Linking)

3.初始化(Initialization)

4.使用(Using)

5.卸载(Unloading)

二、初始化阶段

1.初始化阶段分析

2.类的初始化触发方式

3.不执行初始化指令的特殊情况

4.继承关系下的初始化阶段

总结


前言

JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了类的生命周期、类的初始化阶段等内容。


一、类的生命周期

类的生命周期描述了一个类加载、连接、初始化、使用、卸载的整个过程。

1.加载(Loading)

加载阶段是类的生命周期的起始点。当应用程序首次需要使用某个类时,Java虚拟机(JVM)会负责加载这个类。加载是通过类的加载器(ClassLoader)完成的,它会查找并加载类的二进制数据。这个过程包括将类的字节码从文件系统、JAR文件或网络加载到内存中。

2.连接(Linking)

连接阶段是加载阶段的后续,它包括验证、准备和解析三个子阶段。

  • 验证(Verification):验证阶段主要是确保被加载的类文件数据符合JVM规范,没有安全方面的隐患,以及是否与应用程序的其它部分兼容。验证过程包括文件格式验证、元数据验证、字节码验证和符号引用验证。
  • 准备(Preparation):准备阶段是为类的静态变量分配内存,并设置默认的初始值。需要注意的是,准备阶段并不会执行任何初始化操作。
  • 解析(Resolution):解析阶段是将符号引用转换为直接引用。在Java中,符号引用是一个类的全限定名,而直接引用是一个直接指向内存中的地址的指针。解析阶段发生在运行时,而不是编译时。

3.初始化(Initialization)

初始化阶段是类加载过程中的最后一步,当准备和解析阶段完成后,JVM会执行类的构造器方法,这个方法是由编译器自动收集类中的所有类变量的赋值动作和静态代码块集合来的。需要注意的是,构造器方法中的代码只在类被首次使用时执行一次。

4.使用(Using)

一旦类被成功加载、连接并初始化后,就可以被实例化并用于执行应用程序的业务逻辑。在应用程序运行期间,类可能会被频繁地使用。

5.卸载(Unloading)

当应用程序不再需要某个类时,该类的实例以及与其相关的资源将会被回收,这个过程就是卸载。但是需要注意的是,只有当一个类不再被任何活动对象所引用时,它才会被卸载。另外,JVM的垃圾回收机制(Garbage Collection, GC)负责自动处理类的卸载和资源的回收。

二、初始化阶段

1.初始化阶段分析

初始化阶段是类生命周期中的关键阶段之一,主要涉及静态代码块的执行和静态变量的初始化。这个阶段是在类首次被加载到内存中或者在首次实例化这个类的对象时发生的。

在初始化阶段,会执行静态代码块中的代码,这些代码块在类定义中以static声明的部分。这些代码块仅在类首次被加载时执行一次,主要用于执行一些仅需在类加载时进行的初始化操作,如静态变量的赋值等。

此外,初始化阶段会执行字节码文件中clinit部分的字节码指令。clinit方法是Java编译器自动生成的特殊方法,用于执行所有类级别的初始化操作,包括对静态变量的赋值、静态代码块的执行等。clinit方法的执行顺序与Java源代码中编写的顺序一致,确保了按照源代码的顺序进行初始化。

案例:

public class Demo1 {public static int value = 1;static {value = 2;}public static void main(String[] args) {}
}

字节码信息:

<init>构造方法
mainMain方法
<clinit>初始化阶段执行

clinit部分的字节码指令:

0 iconst_1
1 putstatic #2 <init/Demo1.value : I>
4 iconst_2
5 putstatic #2 <init/Demo1.value : I>
8 return

指令解析:

iconst_1将常量1放入操作数栈
putstatic #2 <init/Demo1.value : I>从操作数栈中获取值设置到静态变量中

初始化步骤:

2.类的初始化触发方式

类的初始化可以通过以下几种方式触发:

  • 访问类的静态变量或静态方法。当程序首次访问类的静态变量或静态方法时,会触发类的初始化。需要注意的是,如果静态变量是final修饰的并且等号右边是常量,则不会触发初始化。

案例:

public class Demo1 {public static void main(String[] args) {int i = Test.i;System.out.println(i);}
}class Test{static {System.out.println("初始化");}public static int i = 0;
}

添加-XX:+TraceClassLoading 参数可以打印出加载并初始化的类。

-XX:+TraceClassLoading

运行结果:

  • 调用Class.forName(String className)方法。这个方法用于动态加载类,当调用该方法时,会触发类的初始化。

Class.forName(String className) 源码:

    @CallerSensitivepublic static Class<?> forName(String var0) throws ClassNotFoundException {Class var1 = Reflection.getCallerClass();return forName0(var0, true, ClassLoader.getClassLoader(var1), var1);}@CallerSensitivepublic static Class<?> forName(String var0, boolean var1, ClassLoader var2) throws ClassNotFoundException {Class var3 = null;SecurityManager var4 = System.getSecurityManager();if (var4 != null) {var3 = Reflection.getCallerClass();if (VM.isSystemDomainLoader(var2)) {ClassLoader var5 = ClassLoader.getClassLoader(var3);if (!VM.isSystemDomainLoader(var5)) {var4.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);}}}return forName0(var0, var1, var2, var3);}private static native Class<?> forName0(String var0, boolean var1, ClassLoader var2, Class<?> var3) throws ClassNotFoundException;

boolean var1参数表示是否初始化这个类:

案例: 

public class Demo1 {public static void main(String[] args) throws ClassNotFoundException {Class<?> demo2 = Class.forName("Test.Demo2");}
}class Demo2 {static {System.out.println("初始化");}
}

运行结果:

  • 创建一个类的对象。当使用new关键字创建一个类的对象时,会触发类的初始化。
  • 执行Main方法的当前类。当Java应用程序的入口点是Main方法时,会自动触发当前类的初始化。

案例: 

public class Demo3 {static {System.out.println("Demo3初始化");}public static void main(String[] args) throws ClassNotFoundException {new Demo4();}
}class Demo4{static {System.out.println("Demo4初始化");}
}

运行结果:

3.不执行初始化指令的特殊情况

在字节码层面,初始化阶段是通过执行clinit方法来完成的。然而,值得注意的是,clinit方法并不是在所有情况下都会出现。以下是一些特定情况下不会执行clinit方法的情况:

  • 如果类中既没有静态代码块,也没有对静态变量进行赋值的语句,那么在加载类时不会执行clinit方法。这是因为clinit方法的目的是执行类级别的初始化操作,而在这种情况下,没有需要进行的初始化工作。

案例: 

public class Demo1 {public static void main(String[] args) {}
}

 字节码信息:

  • 如果类中有静态变量的声明,但没有对其进行赋值的语句,同样不会执行clinit方法。静态变量的初始化需要通过赋值语句来进行,如果只是声明但没有赋值,则不会被初始化。

案例: 

public class Demo1 {public static int i;public static void main(String[] args) {}
}

  字节码信息:

  • 如果静态变量的定义使用了final关键字,这类变量会在准备阶段直接进行初始化,因此在类加载时不会执行clinit方法。这是因为final修饰的静态变量在编译时就已经确定了值,不需要在运行时再进行初始化。

案例: 

public class Demo1 {public static final int i = 1;public static void main(String[] args) {}
}

  字节码信息:

4.继承关系下的初始化阶段

在继承关系下,类的生命周期中的初始化阶段变得更为复杂。子类和父类之间的初始化交互是理解这个过程的关键。

  • 直接访问父类的静态变量:在Java中,静态变量是类级别的变量,它们不属于任何一个对象实例,而是与类本身关联。当我们在子类中直接访问父类的静态变量时,只会触发父类的初始化,而不会触发子类的初始化。这是因为静态变量的初始化是类级别的操作,与子类的实例化过程无关。这种机制确保了父类静态变量的初始化在子类中使用之前已经完成。
  • 子类的初始化clinit调用之前,会先调用父类的clinit初始化方法:在Java字节码层面,类的初始化是通过执行clinit方法完成的。当一个子类被初始化时,它的clinit方法会被调用。但在子类的clinit方法执行之前,父类的clinit方法会被先调用。这种顺序确保了父类中的静态变量和静态代码块在子类使用之前已经完成初始化。这种机制确保了继承关系下的正确初始化顺序,使得子类可以依赖于父类中定义的静态变量和静态代码块。


总结

JVM是Java程序的运行环境,负责字节码解释、内存管理、安全保障、多线程支持、性能监控和跨平台运行。本文主要介绍了类的生命周期、类的初始化阶段等内容,希望对大家有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/600398.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

canvas文字设置(含最大宽度)的示例

查看专栏目录 canvas示例教程100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

Linux tty命令教程:掌握Linux终端的使用(附案例详解和注意事项)

Linux tty命令介绍 tty命令在Linux中是一个简单的实用程序&#xff0c;用于检查连接到标准输入的终端。tty是“teletypewriter”的缩写&#xff0c;但通常被称为终端&#xff0c;它允许您通过将数据&#xff08;您的输入&#xff09;传递给系统并显示系统产生的输出来与系统进…

springboot + vue 前后端加密传输 RSA互相加解密、加签验签、密钥对生成

参考 二、关于PKCS#1和PKCS#8格式密钥 由于Java非对称加解密、加验签都是采用PKCS#8格式的密钥&#xff0c;PKCS#1格式的密钥跑不通&#xff0c;这里先简单介绍一下两者的区别。 1、简介 PKCS#1和PKCS#8是两个不同的数字证书标准。 PKCS#1是一个公钥加密标准&#xff0c;它…

【解决|三方工具】导入 XChart 后提示丢失关于 TMPPro 工具引用

开发平台&#xff1a;Unity 2021 版本 插件版本&#xff1a;XChart 3.0&#xff1a;官方文档 - https://github.com/XCharts-Team/XCharts   问题描述 导入 XChart 插件至 Unity 中出现 目录&#xff1a;Component、Theme 等提示丢失 TMPPro&#xff08;TextMeshPro 工具&…

微信小程序的5种打开页面方式

wx.navigateTo&#xff1a;打开新页面 使用 wx.navigateTo 可以打开一个新的页面&#xff0c;新页面会被放置在当前页面的上层。 wx.navigateTo({url: /pages/nextPage/nextPage });wx.redirectTo&#xff1a;关闭当前页面&#xff0c;打开新页面 使用 wx.redirectTo 关闭当…

2024年,Web3技术的“iPhone时刻”会出现吗?

出品&#xff5c;欧科云链研究院 关于2024年的Web3市场&#xff0c;大多数人目前是持乐观态度的。随着宏观政策稳定&#xff0c;美国和香港地区不断释放加密资产现货ETF的利好&#xff0c;叠加铭文热潮及减半周期临近&#xff0c;市场对Web3及加密资产的兴趣正持续上涨。年后的…

[蓝桥杯学习]树的直径与重心

树的直径 定义 为什么不直接说&#xff08;u,v&#xff09;是两个叶子&#xff0c;可能有如下情况&#xff1a; 这是一条链&#xff0c;且u为根&#xff0c;但&#xff0c;度数为1 下面这个情况是不经过根的。 求解方法 如果设根u的深度为0时&#xff0c;直径就是深度dep[v]…

代码随想录刷题第三十八天| 理论基础 ● 509. 斐波那契数 ● 70. 爬楼梯 ● 746. 使用最小花费爬楼梯

代码随想录刷题第三十八天 动态规划基础理论 斐波那契数 (LC 509) 题目思路&#xff1a; 代码实现&#xff1a; class Solution:def fib(self, n: int) -> int:if n<1: return ndp [0 for _ in range(n1)]dp[1] 1for i in range(2, n1):dp[i] dp[i-1]dp[i-2] …

教学/直播/会议触摸一体机定制_基于展锐T820安卓核心板方案

触控一体机是一种集先进的触摸屏、工控和计算机技术于一体的设备。它取代了传统的键盘鼠标输入功能&#xff0c;广泛应用于教学、培训、工业、会议、直播、高新科技展示等领域。触摸一体机的应用提升了教学、会议和展示的互动性和信息交流。 触摸一体机方案基于国产6nm旗舰芯片…

【Spring实战】23 Spring Actuator 常用的自定义

文章目录 1. 自定义健康指示器2. 自定义端点3. 自定义端点路径4. 自定义 Actuator 端点的访问权限5. 启动服务6. 访问自定义的 custom 端点总结 Spring Actuator 是 Spring 框架的一个模块&#xff0c;为开发人员提供了一套强大的监控和管理功能。上一篇 【Spring实战】22 Spri…

1.5 CHALLENGES IN PARALLEL PROGRAMMING

是什么让并行编程变得困难&#xff1f;有人曾经说过&#xff0c;如果你不关心性能&#xff0c;并行编程很容易。你可以在一小时内编写一个并行程序。但是&#xff0c;如果你不在乎性能&#xff0c;为什么要费心写一个并行程序呢&#xff1f; 这本书解决了在并行编程中实现高性…

C语言全面学习基础阶段01—C生万物

如何学好 C 语言 1. 鼓励你&#xff0c;为你叫好。 C 生万物 编程之本 长远 IT 职业发展的首选 C 语言是母体语言&#xff0c;是人机交互接近底层的桥梁 学会 C/C &#xff0c;相当于掌握技术核心 知识点一竿子打通。 IT 行业&#xff0c;一般每 10 年就有一次变革 40 年间&a…

汽车信息安全--芯片厂、OEM安全启动汇总(2)

目录 1.STM32 X-CUBE-SBSFU 2.小米澎湃OS安全启动 3.小结 在汽车信息安全--芯片厂、OEM安全启动汇总-CSDN博客,我们描述了芯驰E3的安全启动机制,接下来我们继续看其他芯片、OEM等安全启动机制。 1.STM32 X-CUBE-SBSFU 该产品全称Secure Boot and Secure

5.2 Android BCC环境搭建(eadb版 上)

写在前面 eadb即eBPF Android Debug Bridge,它是基于adeb的重构。后者曾随aosp 10发布在platform/external目录下。 一,root权限 这里再HighLight下,当前整个专栏都是基于开发环境来展开的,也就是Android设备需要具有root权限。因此该专栏下每一篇博客都是默认了当前开发…

科锐16位汇编学习笔记01汇编基础和debug使用

为什么学习16位汇编&#xff1f; 16位操作指令最多能够操作两个字节&#xff0c;且更能够体现出与硬件的交互。16位下的指令和32位汇编的指令差不多。16位汇编的指令在32位一样使用.要学好汇编必须要了解一点点硬件知识,16汇编是直接操作硬件,32位汇编指令跟硬件隔离了 硬件运…

UICollection Compositional Layout全详解

本文字数&#xff1a;8325字 预计阅读时间&#xff1a;45分钟 01 Collection View Layout全详解 UICollectionView在iOS中是构建复杂布局的强大工具。iOS13中引入的 UICollectionViewCompositionalLayout为创建自定义布局提供了全新的可能性。本文将深入探讨Compositional Lay…

频率域滤波图像复原之带阻滤波器的python实现——数字图像处理

原理&#xff1a; 带阻滤波器&#xff08;Band-Stop Filter&#xff09;是一种在信号处理领域常用的滤波器&#xff0c;它的主要功能是去除&#xff08;或减弱&#xff09;信号中特定频率范围内的成分&#xff0c;同时允许其他频率范围的信号通过。这种滤波器在多种应用中都非…

C语言中#define的用法详解

C语言中的#define是一个预处理器指令&#xff0c;用于定义常量、宏和条件编译。在本文中&#xff0c;我们将深入探讨#define的各种用法&#xff0c;以及它在C程序中的作用。 1. 定义常量 #define最基本的用法之一是定义常量。通过使用#define&#xff0c;可以在程序中为一个值…

计算机网络——多址复用技术

1. 频分多址&#xff08;FDMA&#xff09; 1.1 基本原理 频率分配&#xff1a;在FDMA系统中&#xff0c;整个可用的频带被分割成多个较小的频带或通道。每个通道分配给一个用户。 时间利用&#xff1a;用户在分配给他们的频道上持续进行通信&#xff0c;不受时间限制。 1.2 优…

云尚办公项目学习

完整的笔记可以参考这个专栏&#xff0c;写的挺详细的&#xff1a;云尚办公课件笔记&#xff0c;come on boy form-create前端组件 formProps记录了表单有哪些表单项&#xff0c;分别是哪些类型&#xff08;下拉&#xff0c;单选&#xff0c;输入框&#xff09; formOptions记…