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.类加载阶段
类的生命周期有如下阶段
-
加载(Loading):在加载阶段,类的字节码被加载到JVM的内存中。这包括从文件系统、网络等位置加载类的字节码,并将其转换为JVM能够理解的数据结构。加载阶段的结果是在方法区(Method Area)创建一个代表该类的Class对象。
-
连接(Linking):连接阶段将加载的类与其他类和资源进行关联,以便正确地解析和执行。连接阶段可以进一步分为三个子阶段:
- 验证(Verification):验证阶段确保类的字节码符合JVM规范,并且不会引发安全问题或错误。
- 准备(Preparation):在准备阶段,为类的静态变量分配内存并初始化为默认值,例如数值类型初始化为0,引用类型初始化为null。
- 解析(Resolution):解析阶段将符号引用(如类、方法、字段的符号名称)解析为直接引用,以便在后续的执行阶段中能够准确访问相关内容。
-
初始化(Initialization):初始化阶段是类生命周期中的关键阶段,它负责执行类的静态初始化代码块和静态变量的赋值。在该阶段,JVM确保静态变量按照预期值进行初始化,静态初始化块被执行,构造器也可以被调用,但仅限于初始化静态字段。初始化阶段标志着类已准备好被使用。
-
使用(Usage):在初始化阶段之后,类就可以被使用了。这包括通过创建对象、调用类的方法、访问静态变量等方式来使用类。
-
卸载(Unloading):如果某个类不再被引用,JVM可能会在某些情况下将其卸载,释放对应的内存和资源。类的卸载是一个可选的过程,通常由垃圾回收器决定。
需要注意的是,类的生命周期可能因为具体的JVM实现、加载方式、类加载器等因素而有所不同。上述阶段的顺序和细节可能会因JVM的版本和配置而有所变化。
从大方面来说分为加载,连接,和初始化阶段。
4.1加载
加载阶段Java虚拟机需要完成以下三件事:
- 通过一个类的全限定名来获取定义此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
- 在内存中生成一个代表这个类的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 信息。
-
instanceKlass(元空间中的类元信息):
instanceKlass
是在HotSpot虚拟机的元空间中存储的一种数据结构,它表示已加载的类的元信息。这个数据结构包含了类的名称、修饰符、方法、字段、父类、接口等信息。在HotSpot的内部实现中,instanceKlass
是用于支持虚拟机的运行时类型信息和方法的查找调用等操作。它和Java中的Class对象类似,但是在内存结构上可能有所不同。 -
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的加载连接和初始化。
相关文章:

JVM——类加载与字节码技术—编译期处理+类加载阶段
3.编译期处理 编译期优化称为语法糖 3.1 默认构造器 3.2 自动拆装箱 java基本类型和包装类型之间的自动转换。 3.3泛型集合取值 在字节码中可以看见,泛型擦除就是字节码中的执行代码不区分是String还是Integer了,统一用Object. 对于取出的Object&…...

C#|如何调试进依赖动态库中
第一步:打开项目属性 第二步 打开debug的本地调试可用 第三步 把要调试的代码拖进主界面打断点就可以进断点了...

全新版本QStack云管系统3.5.3 附详细安装教程
源码介绍: QStack云管系统3.5.3,全新版本下载安装包详细搭建教程。 涵盖了服务器、云主机、代理IP等多种云产品管理运维和安全存储。 同时,QStack还支持对接运营众多公有云厂商产品资源,满足不同用户的需求。 通过开放API和插…...
SLB 负载均衡
优质博文:IT-BLOG-CN 一、简介 SLB (Server Loader Balancer)将访问流量根据转发策略分发到后台多台服务器的流量分发控制服务,来实现多台服务器提供相同的业务服务。负载均衡扩展了应用的服务能力,增强了应用的可用性。主要用于…...

多核调度预备知识
进程调度的本质 任务/进程切换 即:上下文切换,内核对处理器上执行的进程进行切换“上下文” 指:寄存器的值“上下文切换”指: 将寄存器的值保存到内存中(进程被剥夺处理器,停止执行)将另一组寄存器的值从内存中加载到…...
什么是Git?解释Git的分布式版本控制系统的优势?
1、什么是Git?解释Git的分布式版本控制系统的优势? Git是一个开源的分布式版本控制系统,用于跟踪和管理代码库的版本历史。它允许用户在本地计算机上跟踪和管理代码库的更改,并与其他人协作开发项目。Git的分布式特性意味着它不需…...
软考高级系统架构设计师系列论文九十五:图书馆网络应用体系安全设计
软考高级系统架构设计师系列论文九十五:图书馆网络应用体系安全设计 一、网络应用体系安全设计相关知识点二、摘要三、正文四、总结一、网络应用体系安全设计相关知识点 软考高级系统架构设计师:计算机网络...

qt 实现音视频的分贝检测系统
项目场景: 目前的产品经常播放m3u8流,有的视频声音正常,有的视频声音就偏低,即使放到最大音量声音也是比较小,所以就产生了某种需求,能否自动感知视频声音的大小,如果发现声音比较小的情况&…...
SSM框架和Spring Boot+Mybatis框架的性能比较?
SSM框架和Spring BootMybatis框架的性能比较,没有一个绝对的答案,因为它们的性能受到很多因素的影响,例如项目的规模、复杂度、需求、技术栈、团队水平、测试环境、测试方法等。因此,我们不能简单地说哪个框架的性能更好ÿ…...

6个月的测试,来面试居然要18K,我一问连8K都不值
2023年7月份我入职了深圳某家创业公司,刚入职还是很兴奋的,到公司一看我傻了,公司除了我一个自动化测试,公司的测试人员就只有2个开发3个前端1个测试还有2个UI,在粗略了解公司的业务后才发现是一个从零开始的项目&…...

优美而高效:解决服务器通信问题
题目背景 在这个问题中,我们面临着一幅服务器分布图。图中的每个单元格可能有服务器(标记为1)或者没有(标记为0)。我们的任务是找出能够与至少一台其他服务器进行通信的服务器数量。 算法思路 为了解决这个问题&…...
C++模板的模板参数(五)
1.模板的模板参数 在C中,模板的模板参数(Template Template Parameters)是一种特殊的模板参数,允许我们将另一个模板作为模板参数传递给一个模板。这种技术可以用于实现更灵活和通用的模板设计。 模板的模板参数使用两个 “temp…...

基于jeecg-boot的flowable流程加签功能实现
更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: https://gitee.com/nbacheng/nbcio-boot 前端代码:https://gitee.com/nbacheng/nbcio-vue.git 在线演示(包括H5) : http://122.227.135.243:9888 今天我…...

day-03 基于TCP的服务器端/客户端
一.理解TCP和UDP TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种常见的传输层协议,用于在计算机网络中提供可靠的数据传输。 1.TCP: 连接导向:TCP是一种面向连接的…...

匿名对象和一般对象的区别
1.格式的不同 一般对象的格式: Object obj new Object(); 匿名对象的格式: new Object(); 2.作为参数传递机制的不同 2.1先看看一般对象的使用机制 执行步骤: 1.首先程序进入main()函数,执行Object obj,…...

[MyBatis系列⑥]注解开发
🍃作者简介:准大三本科网络工程专业在读,持续学习Java,努力输出优质文章 ⭐MyBatis系列①:增删改查 ⭐MyBatis系列②:两种Dao开发方式 ⭐MyBatis系列③:动态SQL ⭐MyBatis系列④:核心…...

[ACL2023] Exploring Lottery Prompts for Pre-trained Language Models
Exploring Lottery Prompts for Pre-trained Language Models 文章链接 清深的工作,比较有意思的一篇。作者先给出假设,对于分类问题,在有限的语料空间内总能找到一个prompt让这个问题分类正确,作者称之为lottery prompt。为此&…...

【Python编程】将同一种图片分类到同一文件夹下,并且将其分类的路径信息写成txt文件进行保存
注:数据结构同上一篇博文类似 一、代码 import os import cv2 import shutilpath0os.getcwd()\\apple\\RGB path1os.getcwd()\\apple\\tof_confidence # path2os.getcwd()\\apple\\tof_depth # path3os.getcwd()\\apple\\tof_depthRGB # path4os.getcwd()\\apple\…...

单例模式的相关知识
饿汉模式 package Thread; class Singleton{private static Singleton instance new Singleton();public static Singleton getInstance(){return instance;}private Singleton(){} }public class demo1 {public static void main(String[] args) {Singleton S1 Singleton.ge…...

vue问题相关记录
1. vue的 nextTick的原理 首先vue实现响应式并不是数据发生变化后dom立即更新,而是按照一定的策略 异步执行dom更新的。 vue在修改数据后,试图不会立即进行更新,而是要等同一事件循环机制内所有数据变化完成之后,在统一更新 next…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...

2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
鸿蒙(HarmonyOS5)实现跳一跳小游戏
下面我将介绍如何使用鸿蒙的ArkUI框架,实现一个简单的跳一跳小游戏。 1. 项目结构 src/main/ets/ ├── MainAbility │ ├── pages │ │ ├── Index.ets // 主页面 │ │ └── GamePage.ets // 游戏页面 │ └── model │ …...

软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...