JVM——类加载与字节码技术—编译期处理+类加载阶段

3.编译期处理

编译期优化称为语法糖

3.1 默认构造器

3.2 自动拆装箱

java基本类型和包装类型之间的自动转换。

 

3.3泛型集合取值

 

在字节码中可以看见,泛型擦除就是字节码中的执行代码不区分是String还是Integer了,统一用Object. 

对于取出的Object,这个checkcast用于转换Object为Integer类型。 

可以看见局部变量类型表里面包含了方法参数的泛型信息。 

 

 泛型反射

 输出里拿到了两个参数的原始类型List和Map。

这里除了能拿到方法参数上的泛型信息,还能拿到返回值的泛型信息。

 

 

3.4可变参数

 

3.5 foreach 循环

 如果遍历的是List集合,生成代码如下

 

 

3.6 switch 字符串

一个switch变成了两个switch,通过字符串的哈希码进行匹配。

 

 

 

 

3.7 switch 枚举

3.8枚举类

这玩意的本质也是一个class,里面的两个值就是这个class的两个实例对象。

跟普通类的最大区别:普通类的实例个数是无穷,枚举类的实例个数有限。

转换后因为这个class不能再被继承,所以加上了final关键字。并继承了一个支持泛型的枚举父类

 

3.9 try-with-resources

主要作用是简化资源的关闭,只要按照下面的语法在try后面括号内进行资源的创建就可以省略finally中的资源关闭。

编译器会帮助生成finally的代码。 

 

3.10方法重写时的桥接方法

编译器多加了一个真正的方法重写,在其内部调用了我们重写的m方法返回Integer。

该合成方法可以重名,只在jvm内部使用。 

3.11匿名内部类

 额外生成的这个类是外部类名称+$1

 

 因为转换后的类已经变成有两个方法了,所以要加多一个参数接收传进来的x,并传给run方法。

匿名内部类引用外部局部变量必须是finall的原因。 

4.类加载阶段

类的生命周期有如下阶段

  1. 加载(Loading):在加载阶段,类的字节码被加载到JVM的内存中。这包括从文件系统、网络等位置加载类的字节码,并将其转换为JVM能够理解的数据结构。加载阶段的结果是在方法区(Method Area)创建一个代表该类的Class对象。

  2. 连接(Linking):连接阶段将加载的类与其他类和资源进行关联,以便正确地解析和执行。连接阶段可以进一步分为三个子阶段:

    • 验证(Verification):验证阶段确保类的字节码符合JVM规范,并且不会引发安全问题或错误。
    • 准备(Preparation):在准备阶段,为类的静态变量分配内存并初始化为默认值,例如数值类型初始化为0,引用类型初始化为null。
    • 解析(Resolution):解析阶段将符号引用(如类、方法、字段的符号名称)解析为直接引用,以便在后续的执行阶段中能够准确访问相关内容。
  3. 初始化(Initialization):初始化阶段是类生命周期中的关键阶段,它负责执行类的静态初始化代码块和静态变量的赋值。在该阶段,JVM确保静态变量按照预期值进行初始化,静态初始化块被执行,构造器也可以被调用,但仅限于初始化静态字段。初始化阶段标志着类已准备好被使用。

  4. 使用(Usage):在初始化阶段之后,类就可以被使用了。这包括通过创建对象、调用类的方法、访问静态变量等方式来使用类。

  5. 卸载(Unloading):如果某个类不再被引用,JVM可能会在某些情况下将其卸载,释放对应的内存和资源。类的卸载是一个可选的过程,通常由垃圾回收器决定。

需要注意的是,类的生命周期可能因为具体的JVM实现、加载方式、类加载器等因素而有所不同。上述阶段的顺序和细节可能会因JVM的版本和配置而有所变化。

从大方面来说分为加载,连接,和初始化阶段。

4.1加载

加载阶段Java虚拟机需要完成以下三件事:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

java_mirror属性起到桥梁作用(c++数据结构和java的桥梁),java的对象,要想访问它的Klass信息不能直接访问,要通过java_mirror镜像访问。

常用的XXX.class不是指Klass,而是java_mirror。

如果该类有父类或接口没有加载,会先加载父类和接口,才会轮到这个类加载。

类的字节码被加载到元空间,构成instanceKlass数据结构。其中 _java_mirror是java的类镜像,它持有该类在堆内存中的地址,堆内存中的类对象也持有instanceKlass在本地内存中的地址。

用new关键字创建person的实例对象时,每个实例对象都有自己的对象头是16个字节,其中八个字节对应着对象的class地址。

如果要通过实例对象获取其class信息,会先访问对象头,然后通过class地址先找到堆中的类对象,再间接找到元空间的instanceKlass.

 扩展:我们通过类模版创建对象后,此时对象头中有8个字节对应 类模版(class)在堆内存的地址,如果想调用普通方法,或者 get,set 方法就要通过对象头中类模版地址找到元空间中的instanceKlass,再通过instanceKlass获取 field,methods 信息。

  1. instanceKlass(元空间中的类元信息): instanceKlass 是在HotSpot虚拟机的元空间中存储的一种数据结构,它表示已加载的类的元信息。这个数据结构包含了类的名称、修饰符、方法、字段、父类、接口等信息。在HotSpot的内部实现中,instanceKlass 是用于支持虚拟机的运行时类型信息和方法的查找调用等操作。它和Java中的Class对象类似,但是在内存结构上可能有所不同。

  2. Class对象(堆中的类元信息): 在Java中,每个已加载的类都有一个与之对应的Class对象,用来表示类的元信息。Class对象存储了类的名称、修饰符、方法、字段、父类、接口等信息,也支持反射操作。这个Class对象是存在于堆内存中的,它是Java反射机制的核心。

虽然instanceKlass 和Class对象在某种程度上都用来表示类的元信息,但它们的实现和作用在内部有所区别。instanceKlass 主要在HotSpot虚拟机的内部实现中使用,而Class对象是Java编程中常用的反射机制的一部分。这两者的关系是,instanceKlass 是HotSpot虚拟机内部用于支持类的元数据管理的一部分,而Class对象则是供Java程序员在运行时获取和操作类信息的关键工具。

4.2 链接

验证(Verification)

验证阶段确保类的字节码符合JVM规范,并且不会引发安全问题或错误。

 随便修改一下编译后class文件就会验证报错。

准备(Preparation)

在准备阶段,为类的静态变量分配内存并初始化为默认值,例如数值类型初始化为0,引用类型初始化为null。

静态变量跟类对象存储在一起,都在堆中。早期的jvm,静态变量跟着instanceKlass存储在方法区。

 

public class Example {
    static int staticVariable = 42;

    public static void main(String[] args) {
        Example instance = new Example();
        
        // 通过类名访问静态变量
        System.out.println(Example.staticVariable); // 输出: 42
        
        // 通过类对象访问静态变量
        System.out.println(instance.staticVariable); // 输出: 42
    }
}

在这个示例中,通过类对象 instance 访问了静态变量 staticVariable,并且与通过类名直接访问的结果相同。

需要注意的是,尽管在JDK 8及之后版本中支持通过类对象访问静态变量,但这并不是很常见的用法,通常还是使用类名来访问静态变量更加清晰和符合约定。

通过上面代码可以知道,a只是分配了空间,没有赋值。b在准备阶段没有赋值,只是准备好了语句,还要等到初始化阶段,而c,d已经赋完值了。

解析(Resolution)

解析阶段将常量池中的符号引用(如类、方法、字段的符号名称)解析为直接引用,以便在后续的执行阶段中能够准确访问相关内容。

默认情况下,类的加载都是懒惰式的,用到了类C,没有用到类D的话,类D不会主动加载。

 上面代码准备了一个类加载器,调用了loadClass方法加载类C,但这只会,进行类C的加载,不会进行解析和初始化。

new C()会进行C的加载解析和初始化,并把D也给加载解析和初始化。

类D未解析的情况时

 在HSDB中连接到该进程上,只能看见有类C的存在,类C的常量池中可以看见类D前面标注了常量_未经解析类,仅仅是个符号。

new C(),类D被解析时

现在C,D都有了,并且,类C的常量池里面也知道了类D的内存地址。

这就是一个符号引用,一个直接引用。解析阶段就是让符号引用变成直接引用。 

4.3 初始化

初始化阶段是类生命周期中的关键阶段,它负责执行类的静态初始化代码块静态变量的赋值。在该阶段,JVM确保静态变量按照预期值进行初始化,静态初始化块被执行,构造器也可以被调用,但仅限于初始化静态字段。初始化阶段标志着类已准备好被使用。

<cinit>()v方法

初始化即调用<cinit>()V,虚拟机会保证这个类的[构造方法]的线程安全

发生的时机

加载阶段就已经生成了mirror_class(也就是类.class),所以不会触发静态代码块。数组存的也还是Minor对象,在加载时就创建了。

4.4 练习

a,b都不会导致类的初始化,两个都是final的基本类型,在准备阶段就已经赋值了。

c会导致类的初始化,这是包装类型,底层会调用Integer.valueOf(20).

字节码的静态代码块中能看见有关C的操作,说明C是在初始化阶段进行。

 

 单例模式就是保证在jvm中,这个类的对象只有一个。

静态内部类的好处是可以访问外部类的资源,构造方法。所以私有构造方法也可以调用。

只要不调getIntance(),就不会触发LazyHolder的加载连接和初始化。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

骨传导耳机适合运动时佩戴吗?精选五款适合运动时佩戴的耳机

当专业运动耳机已经成了运动新贵们的常用穿戴拍档&#xff0c;给夜跑、骑行、撸铁增添了更多期待和振奋。而骨传导耳机凭借自身健康、舒适、安全的聆听方式,迅速脱颖而出成为运动健身中最健康的黑科技耳机&#xff0c;但由于市面上的骨传导耳机技术参差不齐&#xff0c;一不留神…

SQL查询结果数字转字符串,以及查询结果的的四舍五入

最近在工作中碰到了SQL进行查询&#xff0c;碰到了SQL查询结果位数字型&#xff0c;需要把数字转化为字符串来进行下一步工作&#xff0c;整理结果如下: 先看图&#xff1a; 我们需要的查询data_val的和&#xff0c;这样的查询SQL如下: select sum(data_val) from 表名 where …

js 小程序限流函数 return闭包函数执行不了

问题&#xff1a; 调用限流 &#xff0c;没走闭包的函数&#xff1a; checkBalanceReq&#xff08;&#xff09; 业务逻辑&#xff1a; 1.限流函数&#xff1a;loadshMy.js // 限流 const throttle (fn, context, interval) > {console.log(">>>>cmm …

【洛谷算法题】P1000-超级玛丽游戏【入门1顺序结构】

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P1000-超级玛丽游戏【入门1顺序结构】&#x1f30f;题目描述&#x1f30f;输入格…

10张图让你彻底理解回调函数

不知你是不是也有这样的疑惑&#xff0c;我们为什么需要回调函数这个概念呢&#xff1f;直接调用函数不就可以了&#xff1f;回调函数到底有什么作用&#xff1f;程序员到底该如何理解回调函数&#xff1f; 这篇文章就来为你解答这些问题&#xff0c;读完这篇文章后你的武器库…

Multisim中VDAC8使用

1.Multisim中VDAC8是8位DAC。双击打开后&#xff0c;数字“1”代表I/O口输入电压高于2.8V有效&#xff0c;数字“0”代表代表I/O口输入电压低于0.8V有效。 2.为控制输出电压&#xff0c;点击开关不同按钮可以调节输出值。

Docker部署MongoDB 5.0.5

1、查看目录 rootwielun:~# tree mongo mongo ├── conf │ └── mongod.conf ├── data ├── docker-compose.yml └── logrootwielun:~# cd mongo rootwielun:~/mongo# chmod 777 log2、配置docker-compose.yml rootwielun:~/mongo# cat docker-compose.yml ve…

Maven详解

文章目录 一、引言1.1 为什么需要 Maven&#xff1f;1.2 Maven 解决了哪些问题&#xff1f;1.2.1 添加第三方jar包1.2.2 jar包之间的依赖关系1.2.3 处理jar包之间的冲突1.2.4 获取第三方jar包1.2.5 将项目拆分成多个工程模块1.2.6 实现项目的分布式部署 二、介绍三、Maven 的特…

vscode+ros开发环境搭建

目录 介绍 前提 vscode安装 vscode插件安装 工作空间准备 打开vscode 创建catkin包 编写cpp代码 编译 运行 启动ros服务 监听话题 启动ros测试 介绍 ros开发是机器人开发中必不可少的工作&#xff0c;语言选择可以是c,也可以是python。工具的话&#xff0c;不能像wi…

【3ds Max】练习——制作衣柜

目录 步骤 一、制作衣柜顶部 二、制作衣柜门板 三、制作衣柜底部 四、制作柜子腿部 五、制作柜子底板 步骤 一、制作衣柜顶部 1. 首先创建一个平面&#xff0c;然后将图片素材拖入平面 2. 平面大小和图片尺寸比例保持一致 3. 单机鼠标右键&#xff0c;选择对象属性 勾选…

如何把aac转化为mp3?大家和我一起往下学习

如何把aac转化为mp3&#xff1f;aac是一种先进的音频编码格式&#xff0c;通过较小的文件大小提供出色的音质体验。然而&#xff0c;由于其相对较少的普及度&#xff0c;与MP3相比&#xff0c;兼容性稍显不足&#xff0c;有些播放器可能无法直接识别aac格式。在某种程度上&…

USB Type-C端口集成式ESD静电保护方案 安全低成本

Type-C端口是根据USB3.x和USB4协议传输数据的&#xff0c;很容易受到电气过载&#xff08;EOS&#xff09;和静电放电&#xff08;ESD&#xff09;事件的影响。由于Type-C支持随意热插拔功能&#xff0c;其内部高集成度的芯片&#xff0c;更容易受到人体静电放电的伤害和损坏。…

.netcore windows app启动webserver

创建controller: using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json.Serialization; using System.Threading.Tasks;namespace MyWorker.…

【linux内核】DP83867添加GMII模式支持

文章目录 修改方案前期知识为什么这么修改&#xff1f;通用寄存器 修改方案 linux 4.0内核下/drivers/net/phy/dp83867.c phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, val);} if (phydev->interface PHY_INTERFACE_MODE_GMII){val phy_read_mmd(phydev, DP838…

微短剧赛道风口下的一站式点播解决方案

微短剧行业正风生水起。 一种全新的剧集模式正迅速崛起&#xff0c;并引起广泛关注。 从线下电影院的“巨幕”到PC端“网络大电影”&#xff0c;从“长视频”再到如今移动端1-3分钟的“微短剧”&#xff0c;影视行业在过去几年经历了一场深刻又显著的变化。 微短剧&#xff0…

网络丢包故障如何定位?如何解决?

引言 本期分享一个比较常见的网络问题--丢包。例如我们去ping一个网站&#xff0c;如果能ping通&#xff0c;且网站返回信息全面&#xff0c;则说明与网站服务器的通信是畅通的&#xff0c;如果ping不通&#xff0c;或者网站返回的信息不全等&#xff0c;则很可能是数据被丢包了…

Android OpenCV(七十五): 看看刚”转正“的条形码识别

前言 2021年,我们写过一篇《OpenCV 条码识别 Android 平台实践》,当时的条形码识别模块位于 opencv_contrib 仓库,但是 OpenCV 4.8.0 版本开始, 条形码识别模块已移动到 OpenCV 主仓库,至此我们无需自行编译即可轻松地调用条形码识别能力。 Bar code detector and decoder…

C++ Day3

目录 一、类 【1】类 【2】应用实例 练习&#xff1a; 【3】封装 二、this指针 【1】this指针的格式 【2】必须使用this指针的场合 三、类中的特殊成员函数 【1】构造函数 i&#xff09;功能 ii&#xff09;格式 iii&#xff09;构造函数的调用时机 iv&#xff09;…

面试官:策略模式有使用过吗?我:没有......

面试官&#xff1a;策略模式有使用过吗&#xff1f;我&#xff1a;没有… 何为策略模式&#xff1f; 比如在业务逻辑或程序设计中比如要实现某个功能&#xff0c;有多种方案可供我们选择。比如要压缩一个文件&#xff0c;我们既可以选择 ZIP 算法&#xff0c;也可以选择 GZIP…

【云计算】Docker特别版——前端一篇学会

docker学习 文章目录 一、下载安装docker&#xff08;一&#xff09;Windows桌面应用安装&#xff08;二&#xff09;Linux命令安装 二、windows注册登录docker三、Docker的常规操作(一)、基本的 Docker 命令(二)、镜像操作(三)、容器的配置(四)、登录远程仓库 四、镜像管理(一…