Java类的生命周期-初始化阶段

news2024/11/18 20:30:33

Java类的生命周期-初始化阶段


前两篇讲述了类生命周期的加载阶段和连接阶段,那么本篇我们来讲最为重要的初始化阶段,借助字节码文件与大厂面试题更好的理解类的初始化

头篇提到,类的生命周期可疑将他分为五个阶段,本篇要讲述的就是第三阶段-初始化阶段:

加载
连接
初始化
使用
卸载

初始化作用

在初始化阶段会执行静态代码块并且为静态变量赋值,其最核心的部分就是执行字节码文件中的clinit部分
我们以一个类的初始化为例:

public class InitTest {
    public static int value = 0;
    static {
        value = 2;
    }

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

我们在类中声明了一个静态字段,赋值为0,在下面的静态代码块中又将值修改为2

编译过后我们打开他的字节码文件
如果你不会使用打开字节码文件的工具,本篇末尾会附有教程
字节码文件中会出现三个方法
在这里插入图片描述

  • init是构造方法,这里没有写构造方法但是他会默认生成一个无参构造
  • main就是我们的主方法
  • clinit就是在初始化阶段执行的初始化方法

打开clinit方法就可以看到他的字节码指令:

0 iconst_0
1 putstatic #2 <InitTest.value : I>
4 iconst_2
5 putstatic #2 <InitTest.value : I>
8 return

iconst指令是将常量0放入操作数栈中,putstatic指令又将操作数栈中的数字放入上一阶段为静态字段开辟好的内存中,静态字段的名字在常量池中寻找,此处为#2,即对应常量池中的2号索引,下面两句也是同样操作,最后静态变量value的值就成了2。


若是此时将代码中的两次赋值顺序颠倒:

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

那么此时clinit方法的字节码指令就变成了:

0 iconst_2
1 putstatic #2 <InitTest.value : I>
4 iconst_0
5 putstatic #2 <InitTest.value : I>
8 return

就会发现字节码文件中的执行顺序也发生了颠倒,此时说明字节码指令的执行顺序与代码编写顺序是一致的


初始化条件

初始化阶段并不是一定会执行,他只在四种情况下进行初始化:

  1. 访问一个类的静态变量或静态方法,但是final修饰的静态字段不会触发初始化
  2. 调用Class.forName(String className)时
  3. new一个该类的对象时
  4. 执行该类的Main方法时

初始化方法clinit在下面三种情况下不会出现

  1. 无静态代码块且无静态变量赋值语句
  2. 有静态变量的声明,但是没有赋值语句
  3. 静态变量由final进行修饰

涉及到子类继承父类时,初始化执行有两种情况

  1. 直接访问父类的静态变量,不会触发子类的初始化
  2. 子类初始化clinit调用之前,会先调用父类的初始化

大厂面试题

题目如下,写出控制台的输出内容:

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");
    }
}

执行main方法时,会对类进行初始化,所以我们可以看一下初始化方法clinit中的字节码指令:

0 getstatic #1 <java/lang/System.out : Ljava/io/PrintStream;>
3 ldc #9 <D>
5 invokevirtual #3 <java/io/PrintStream.println : (Ljava/lang/String;)V>
8 return

其内容就是在执行静态代码块中的内容,ldc指令将常量池中的字符串D加载到操作数栈中,而invokevirtual指令是调用println方法将其打印出来。

初始化完毕后,他会执行main方法中的内容,首先打印A,随后new了两个Test1的对象,前面说过在new对象时,类也会进行初始化,但是类在执行时至多只会进行一次初始化,所以这里不需要再次执行初始化方法,所以此时会调用两次构造方法,我们查看init方法中的字节码指令:

 0 aload_0
 1 invokespecial #6 <java/lang/Object.<init> : ()V>
 4 getstatic #1 <java/lang/System.out : Ljava/io/PrintStream;>
 7 ldc #7 <C>
 9 invokevirtual #3 <java/io/PrintStream.println : (Ljava/lang/String;)V>
12 getstatic #1 <java/lang/System.out : Ljava/io/PrintStream;>
15 ldc #8 <B>
17 invokevirtual #3 <java/io/PrintStream.println : (Ljava/lang/String;)V>
20 return

第3-5行与6-8行为主要内容,其字节码指令与clinit中相似,此时发现字节码指令会先打印C再打印B,所以初始化代码块会在构造方法之前执行,那最后的输出顺序为:DACBCB

第二题

public class Test2 {
    public static void main(String[] args) {
        System.out.println(B.a);
    }
}
class A{
    static int a = 0;
    static {
        a = 1;
    }
}
class B extends A{
    static {
        a = 2;
    }
}

大家可以在评论区讨论一下输出的a的值是多少


附:字节码工具

1.在IDEA中下载插件:jclasslib

在这里插入图片描述
下载并应用

2.点击视图->Show ByteCode By Jclasslib

注意此时光标要停留在你想查看字节码文件的源代码上
在这里插入图片描述

3.查看字节码文件

此时就可以查看字节码文件的常量池、方法、字段等信息
在这里插入图片描述


看到这里对你有帮助请点一个关注,如果不太明白可以查看一下之前的两篇,学习一下前两个阶段

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

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

相关文章

RIP路由(已被淘汰)

一、rip 路由原理 RIP&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;早期的动态路由协议&#xff0c;被广泛应用于TCP/IP网络中&#xff0c;尤其是在中小型网络中。基于距离矢量&#xff08;Distance-Vector&#xff09;算法来计算到达目的网络…

农场小程序带你走进生态农产品的世界

在快节奏的现代生活中&#xff0c;人们对食品安全的关注日益增强&#xff0c;对环境、健康农产品的需求也愈发迫切。然而&#xff0c;传统农产品市场往往信息不透明&#xff0c;消费者难以直接了解农产品的生长环境和生产过程&#xff0c;导致信任缺失。而农场小程序的出现&…

工程安全监测分析模型与智能算法模型方案

工程安全监测分析模型与智能算法模型 构建大坝安全监测智能分析模型&#xff0c;以大坝立体智能感知体系为依托&#xff0c;获取大坝变形、渗流渗压、环境变量等实时监测数据&#xff0c;作为模型输入&#xff0c;实现监测数据自动预处理、特征提取、误差分析、变化趋势分析等…

大模型增量训练--基于transformer制作一个大模型聊天机器人

针对夸夸闲聊数据集&#xff0c;利用UniLM模型进行模型训练及测试&#xff0c;更深入地了解预训练语言模型的使用方法&#xff0c;完成一个生成式闲聊机器人任务。 项目主要结构如下&#xff1a; data 存放数据的文件夹 dirty_word.txt 敏感词数据douban_kuakua_qa.txt 原始语…

Qt——如何创建一个项目

前言 本文主要通过实操带领大家来实现基础文件的操作&#xff0c;主要包括文件的打开&#xff0c;读取&#xff0c;写入&#xff0c;当然文件读写我们可以有几种不同的方式来进行操作&#xff0c;分别是文件流&#xff0c;字节流来进行的操作这里就需要两个类分别是文件流&…

迈威通信闪耀工博会,以创新科技赋能工业自动化

昨日&#xff0c;在圆满落幕的第24届中国国际工业博览会上&#xff0c;迈威通信作为工业自动化与智慧化领域的先行者&#xff0c;以“创新打造新质通信&#xff0c;赋能工业数字化”为主题精彩亮相&#xff0c;向全球业界展示了我们在工业自动化领域的最新成果与创新技术。此次…

elementUI表格中某个字段(state)使用计算属性进行转换为对应中文显示

代码案例&#xff1a; <template><el-table:data"tableData"style"width: 100%"><el-table-columnprop"date"label"日期"width"180"/><el-table-columnprop"name"label"姓名"wid…

count(1),count(*)与 count(‘列名‘) 的区别

文章目录 COUNT(expr)性能对比count(*) VS count(1)count(*) VS count(列名) count(*)会走索引吗MyISAM count优化InnoDB如何处理count(*)总结 参考官方文档&#xff1a; https://dev.mysql.com/doc/refman/8.4/en/aggregate-functions.html#function_count COUNT(expr) coun…

叶国富“推翻”马云新零售,零售新王此刻登基?

63亿入主永辉超市&#xff0c;拿到29.4%股份&#xff0c;坐上永辉超市第一大股东的宝座&#xff0c;名创优品创始人叶国富&#xff0c;成为了新科“零售之王”。 很是霸气外漏。 有投资者表示费解&#xff0c;不明白为何此时入局超市行业&#xff0c;叶国富当即召开电话会议&…

数据结构:树的定义及其性质

树的定义 树是一种重要的非线性数据结构&#xff0c;树作为一种逻辑结构&#xff0c;同时也是一种分层结构。具有以下两个特点&#xff1a; 1.树的根结点没有前驱&#xff0c;除根结点意外的节点只有一个前驱 2.树中所有结点都可以有0个或多个后继 树结构在多个领域都有广泛…

JVM相关的命令汇总

一、简介 虽然目前市场上有很多成熟的 JVM 可视化监控分析工具&#xff0c;但是所有的工具其实都依赖于 JDK 的接口和底层相关的命令&#xff0c;了解这些命令的使用对于在紧急情况下排查 JVM 相关的线上故障&#xff0c;会有更加直观的帮助。 下面一起来看看 JVM 常用的命令…

ARM硬件知识补充

一、硬件知识 1.三极管 三极管定义&#xff1a;全称应为半导体三极管&#xff0c;也被称为双极型晶体管或晶体三极管。 主要功能&#xff1a;是将微弱的电信号放大成幅度值较大的电信号&#xff0c;同时也被用作无触点开关。 分类&#xff1a;分为NPN型和PNP型两种类型。 …

GNSS定位中自适应调整电离层延迟参数过程噪声的方法

文章目录 前言一、非差非组合PPP模型二、电离层功率谱密度计算三、具体实现方法3.1 不平滑3.2 三阶多项式平滑 参考文献 前言 GNSS定位中不少技术手段如PPP和长基线RTK需要将电离层延迟作为参数估计&#xff0c;电离层延迟的变化通常被描述为随机游走过程&#xff0c;而功率谱密…

three.js 通过着色器实现热力图效果

three.js 通过着色器实现热力图效果 在线预览 https://threehub.cn/#/codeMirror?navigationThreeJS&classifyshader&idheatmapShader 在 https://threehub.cn 中还有很多案例 <!doctype html> <html lang"en"> <head> <meta charse…

RFID标签的前世今生

一、RFID标签发展历程 1.1 技术突破 RFID标签技术自20世纪90年代兴起以来&#xff0c;经历了多次重要的技术突破&#xff0c;这些突破极大地推动了RFID技术的发展和应用。 标签供电方式的革新&#xff1a;早期的RFID标签主要依赖于电磁感应线圈进行短暂供电&#xff0c;而现…

python中的assert语句

1.什么是assert 程序运行过程中,所有变量的当前值组合构成了“状态“; 每执行一段程序,状态就发生变化;如果程序有逻辑错误的bug,必定在处变量值的组合不符合预期,处于错误状态; 将对变量的预期写为断言,可以定位复杂的逻辑错误。 语法: assert <表达式> [, …

transition在vue2和vue3中的差异

背景&#xff1a; 在学习<transition/> 的时候&#xff0c;发现自己跟着视频抄写的代码&#xff0c;实现效果和示例代码不一致。 代码&#xff1a; <template><div id"app"><button id"btn" click"changeShow">切换…

Cholesky分解

Cholesky 应该怎么念&#xff0c;o(╯□╰)o&#xff0c;我感觉比较像‘瞅乐死骑’&#xff0c;毕竟这是 名字&#xff0c;哈哈哈哈 ATA 这个矩阵非常重要&#xff0c;之前在最小二乘法也见过它&#xff0c;如果&#xff1a; Axb 无解&#xff0c;也就是 xA−1b 不成立&…

随笔:创新的路径

最近&#xff0c;中国工业博览会在上海召开了&#xff0c;许多自动化行业的朋友都去参加这一场中国工业的盛会&#xff0c;兴奋地传来了各种新技术和新产品的消息。总的感觉国产产品集中度很高&#xff0c;长的都差不多。同质化现象比较严重。要实现产品的差异化&#xff0c;唯…

英伟达Blackwell系列显卡揭秘:RTX 5090与RTX 5080引领性能新高度

在万众瞩目的期待中&#xff0c;9月27日传来震撼消息&#xff0c;知名硬件信息揭秘者Kopite7kimi再次出手&#xff0c;独家披露了英伟达即将震撼登场的Blackwell系列显卡中的两款旗舰级产品——GeForce RTX 5090与RTX 5080的详细规格。这一爆料不仅揭示了英伟达新一代显卡的卓越…