深入浅出JVM(四)之类文件结构
深入浅出JVM(四)之类文件结构
Java文件编译成字节码文件后,通过类加载机制到Java虚拟机中,Java虚拟机能够执行所有符合要求的字节码,因此无论什么语言,只要能够编译成符合要求的字节码文件就能够被Java虚拟机执行
Java虚拟机和字节码是语言、平台无关性的基石
本篇文章将深入浅出的解析字节码文件
无关性的基石
曾经: 源代码->经过编译->本地机器码
Java: 源代码->经过编译->字节码 -> 解释器 -> 本地机器码
字节码: 与操作系统和机器指令集无关的,平台中立的程序编译后的存储格式
字节码是无关性的基石
平台无关性的基石:
- 所有平台都统一支持字节码
- 不同的Java虚拟机都可以执行平台无关的字节码
因此实现了 一次编译,到处运行
语言无关性的基石:
- Java虚拟机
- 字节码
Java虚拟机不是只可以执行Java源代码编译而成的字节码,只要符合要求(安全...)的字节码,它都可以执行
因此Kotlin...等语言可以运行在Java虚拟机上
Class类文件结构
文件格式存取数据的类型
- 无符号数 : u1,u2,u4,u8代表1,2,4,8个字节的无符号数(可以表示数字,UTF-8的字符串,索引引用....)
- 表: 由n个无符号数或n个表组成(命名以
_info结尾)
初识Class文件格式
编写Java源代码
public class Test {private int m;private final int CONSTANT=111;public int inc() throws Exception {int x;try {x = 1;return x;}catch (Exception e){x = 2;return x;}finally{x = 3;}}}
使用可视化工具classpy查看反编译的结果
每个集合前都有一个计数器来统计集合中元素的数量
Class文件格式的描述
| 数据类型 | 名称 | 数量 | 对应图中名字 | 作用 |
|---|---|---|---|---|
| u4 | magic | 1 | 魔数 | 确定这个文件是否是一个能被虚拟机接受的Class文件 |
| u2 | minor_version | 1 | 次版本号 | 虚拟机必须拒绝执行超过其版本号的Class文件 |
| u2 | major_version | 1 | 主版本号 | 虚拟机必须拒绝执行超过其版本号的Class文件 |
| u2 | constant_pool_count | 1 | 常量池容量计数器 | 统计常量数量 |
| cp_info | constant_pool | constant_pool_count - 1 | 常量池 | 存放常量 |
| u2 | access_flags | 1 | 访问标志 | 识别类(类,接口)的访问信息 |
| u2 | this_class | 1 | 类索引 | 确定类的全限定名 |
| u2 | super_class | 1 | 父类索引 | 确定父类的全限定名 |
| u2 | interfaces_count | 1 | 接口计数器 | 统计该类实现接口数量 |
| u2 | interfaces | interfaces_count | 接口索引集合 | 描述该类实现了的接口 |
| u2 | fields_count | 1 | 字段表集合计数器 | 统计类的字段数量 |
| field_info | fields | fields_count | 字段表集合 | 描述类声明的字段(类变量,实例变量) |
| u2 | methods_count | 1 | 方法表集合计数器 | 统计类的方法数量 |
| method_info | methods | methods_count | 方法表集合 | 描述类声明的方法 |
| u2 | attribute_count | 1 | 属性表集合计数器 | 统计属性数量 |
| attribute_info | attributes | attributes_count | 属性表集合 | 描述属性 |
魔数与主次版本号
魔数: 确定这个文件是否为一个能被虚拟机接受的有效Class文件
主次版本号: 虚拟机拒绝执行超过其版本号的Class文件
- 不同版本的Java前端编译器编译生成对应的Class文件主次版本号不同
- 支持高版本JVM执行低版本前端编译器生成的Class文件(向下兼容)
- 拒绝低版本JVM执行高版本前端编译器生成的Clsss文件
常量池
常量池包含两大常量: 字面量和符号引用
符号引用与直接引用
符号引用
- 使用一组符号描述引用(为了定位到目标引用)
- 与虚拟机内存布局无关
- 还是符号引用时目标引用不一定被加载到内存
直接引用
- 直接执行目标的指针,相对偏移量或间接定位目标引用的句柄
- 与虚拟机内存布局相关
- 解析直接引用时目标引用已经被加载到内存中
字面量与符号引用
字面量
- 文本字符串
- 被final声明的常量
符号引用
- 全限定名
- 方法或字段的简单名称和描述符
图中的常量有我们代码中熟悉的常量也有很多没有显示出现在代码中的常量
访问标志
用于识别类或接口的访问信息
是否是一个接口,枚举,模块,注解...
是否被final(public,abstract...)修饰
ACC_PUBLIC:被public修饰
ACC_SUPER: 允许使用invokespecial字节码指令
类索引,父类索引与接口索引集合
类索引
用于确定本类的全限定名
类索引指向常量池中表示该类的符号引用
父类索引
用于确定父类的全限定名

父类索引指向常量池中表示该类父类的符号引用
除了Object外,所有类的父类索引都不为0
接口索引集合
描述这个类实现了哪些接口
我们的例子中没有实现接口,就没有(接口索引集合计数器为0)
总结
Class文件由 类索引,父类索引,接口索引集合 来确定该类的继承关系
字段表集合
描述类声明的字段
字段包括类变量和成员变量(实例变量),不包括局部变量

简单名称和描述符
简单名称
- 字段: 没有描述字段类型的名称
- 方法: 没有描述参数列表和返回类型的名称
描述符
字段: 描述字段的类型
方法: 描述参数列表和返回值
描述符字符含义(long,boolean,对象类型是J,Z,L 其他都是首字母大写)
标识字符 含义 B byte C char D double F float I int J long S short Z boolean V void L 对象类型,如Ljava/lang/Object 描述符描述n维数组
在前面先写n个
[再写标识字符比如java.lang.Integer[ ] =>
[Ljava.lang.Integer
描述符描述方法
参数列表按照从左到右的顺序写在
()中返回类型写到最后
比如String method(long[],int,String[]) =>
([JIL[java.lang.String)Ljava.lang.String
因此Class文件中字段描述符指向常量池中的#07 I 符号引用(的索引)
注意
字段表集合不会列出父类或父接口中声明的字段
只用 简单名称 来确定字段,所以不能有重名字段
用 简单名称 和 描述符 确定方法,所以方法可以重名(重载)
- 字节码文件 规定 简单名称+描述符相同才是同一个方法
- 但是 Java语法 规定 重载 = 简单名称相同 + 描述符的参数列表不同 + 描述符的返回类型不能不同
方法表集合
描述类声明的方法
与字段表集合类似

注意
方法表集合中不会列出父类方法信息(不重写的情况)
属性表集合
属性比较多,这里只说明我们例子中出现的,其他的会总结
用于描述某些场景专有信息
刚刚在字段,方法表集合中都可以看到属性表集合,说明属性表集合是可以被携带的
怎么没看到Java源代码中的代码呢?
实际上它属于属性表集合中的Code属性
Code属性
Java源代码中方法体中的代码经过编译后编程字节码指令存储在Code属性内
其中的异常表集合代表 编译器为这段代码生成的多条异常记录,对应着可能出现的代码执行路径
(程序在try中不抛出异常会怎么执行,抛出异常又会怎么执行....)

Exceptions属性
列举出方法中可能抛出的检查异常(Checked Exception),也就是方法声明throws关键字后面的列举异常

LineNumberTable属性
描述Java源码行号与字节码指令行号(字节码偏移量)对应关系
SourceFile属性
记录生成此Class文件的源码名称
StackMapTable属性
虚拟机类加载验证阶段的字节码验证时,不需要再检验了,只需要查看StackMapTable属性中的记录是否合法
编译阶段将一系列的验证类型结果记录在StackMapTable属性中

ConstantValue
在类加载的准备阶段,为静态变量(常量)赋值
只有类变量才有这个属性
实例变量的赋值: 在实例构造器
类变量的赋值: 在类构造器 或 带有ConstantValue属性在类加载的准备阶段
如果类变量被final修饰(此时该变量是一个常量),且该变量数据类型是基本类型或字符串,就会生成ConstantValue属性,该属性指向常量池中要赋值的常量,在类加载的准备阶段,直接把在常量池中ConstantValue指向的常量赋值给该变量
总结所有属性
| 属性名 | 作用 |
|---|---|
| Code | 方法体内的代码经过编译后变为字节码指令存储在Code属性中 |
| Exceptions | 列举出方法可能抛出的检查异常(Checked Exception) |
| LineNumberTable | Java源码行号与字节码偏移量(字节码行号)对应关系 |
| LocalVariableTable | Java源码定义的局部变量与栈帧中局部变量表中的变量对应关系(局部变量名称,描述符,局部变量槽位置,局部变量作用范围等) |
| LocalVariableTypeTable | 与LocalVariableTable相似,只是把LocalVariableTable的描述符换成了字段的特征签名(完成对泛型的描述) |
| SourceFile | 记录生成这个Class文件的源码文件名称 |
| SourceDebugExtension | 用于存储额外的代码调式信息 |
| ConstantValue | 在类加载的准备阶段,为静态变量(常量)赋值 |
| InnerClasses | 记录内部类与宿主类之间的关系 |
| Deprecated | 用于表示某个字段,方法或类已弃用 (可以用注解@deprecated表示) |
| Synthetic | 用于表示某字段或方法不是由Java源代码生成的,而是由编译器自行添加的 |
| StackMapTable | 虚拟机类加载验证阶段的字节码验证时,不需要再检验了,只需要查看StackMapTable属性中的记录是否合法 |
| Signature | 记录泛型签名信息 |
| BootstrapMethods | 保存动态调用(invokeeddynamic)指令引用的引导方法限定符 |
| MethodParameters | 记录方法的各个形参名称与信息 |
javap解析Class文件
关于javac
javac xx.java 编译Java源文件,不会生成对应的局部变量表
javac -g xx.java 编译Java源文件,生成对应的局部变量表
idea中编译Java源文件使用的是javac -g
关于javap

常用
javap -v 基本上可以反汇编出Class文件中的很多信息(常量池,字段集合,方法集合...)
但是它不会显示私有字段或方法的信息,所以可以使用javap -v -p
详解javap -v -p
public class JavapTest {private int a = 1;float b = 2.1F;protected double c = 3.5;public int d = 10;private void test(int i){i+=1;System.out.println(i);}public void test1(){String s = "test1";System.out.println(s);}}



最后(不要白嫖,一键三连求求拉~)
本篇文章笔记以及案例被收入 gitee-StudyJava、 github-StudyJava 感兴趣的同学可以stat下持续关注喔~
有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~
关注菜菜,分享更多干货,公众号:菜菜的后端私房菜
本文由博客一文多发平台 OpenWrite 发布!
相关文章:
深入浅出JVM(四)之类文件结构
深入浅出JVM(四)之类文件结构 Java文件编译成字节码文件后,通过类加载机制到Java虚拟机中,Java虚拟机能够执行所有符合要求的字节码,因此无论什么语言,只要能够编译成符合要求的字节码文件就能够被Java虚拟…...
Anaconda下的pkgs占用空间13G,如何安全的清理(已解决)
方法一:让Anaconda自行决定清理 执行命令 conda clean -p 我的Anaconda安装在D盘,具体位置如下。你的应该也能找到对应的位置 D:\*****\**\Anaconda3\pkgs (base) C:\Users\Liu_J>conda clean -p WARNING: C:\Users\***\.conda\pkgs does not ex…...
压缩感知常用的重建算法
重建算法的基本概念 在压缩感知(Compressed Sensing, CS)框架中,重建算法是指将从原始信号中以低于奈奎斯特率采集得到的压缩测量值恢复成完整信号的数学和计算过程。由于信号在采集过程中被压缩,因此重建算法的目标是找到最符合…...
c语言经典测试题2
1.题1 我们来思考一下它的结果是什么? 我们来分析一下:\\是转义为字符\,\123表示的是一个八进制,算一个字符,\t算一个字符,加上\0,应该有13个,但是strlen只计算\0前的字符个数。所以…...
⭐北邮复试刷题105. 从前序与中序遍历序列构造二叉树__递归分治 (力扣每日一题)
105. 从前序与中序遍历序列构造二叉树 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示例 1: 输入: preorder [3,9,20,15,7], inorder [9,3,15,…...
机房预约系统(个人学习笔记黑马学习)
1、机房预约系统需求 1.1系统简介 学校现有几个规格不同的机房,由于使用时经常出现“撞车“现象,现开发一套机房预约系统,解决这一问题。 1.2身份简介 分别有三种身份使用该程序 学生代表:申请使用机房教师:审核学生的预约申请管理员:给学生、教师创建账…...
7、内网安全-横向移动PTH哈希PTT票据PTK密匙Kerberos密码喷射
用途:个人学习笔记,有所借鉴,欢迎指正 目录 一、域横向移动-PTH-Mimikatz&NTLM 1、Mimikatz 2、impacket-at&ps&wmi&smb 二、域横向移动-PTK-Mimikatz&AES256 三、域横向移动-PTT-漏洞&Kekeo&Ticket 1、漏…...
【前端】夯实基础 css/html/js 50个练手项目(持续更新)
文章目录 前言Day 1 expanding-cardsDay 2 progress-steps 前言 发现一个没有用前端框架的练手项目,很适合我这种纯后端开发夯实基础,内含50个mini project,学习一下,做做笔记。 项目地址:https://github.com/bradtr…...
ELK入门(四)-logstash
Logstash Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的存储库中。 Logstash 能够动态地采集、转换和传输数据,不受格式或复杂度的影响。利用 Grok 从非结构化数据中…...
laravel-admin的3个开发细节调整
在使用laravel-admin开发的过程中,根据官方开发文档Laravel admin | laravel-admin基本都能实现想要的效果,这里补充3个文档上没有描述的细节 Laravel8命令行创建控制器调整 在laravel-admin中可以使用php artisan admin:make UserController --modelAp…...
Redis--原理篇-数据结构(底层)
Redis数据结构 动态字符串SDS IntSet 统一大小并且内存地址连续 为了方便寻址 Dict 基本结构 扩容 收缩 Ziplist(P150 后半部分再看) Quicklist skiplist(满足中间查询 RedisObject...
OpenAI发布Sora模型,可根据文字生成逼真AI视频
早在2022年11月30日,OpenAI第一次发布人工智能聊天机器人ChatGPT,随后在全世界掀起了人工智能狂潮,颠覆了一个又一个行业。在过去的一年多的时间里,chatGPT的强大功能改变了越来越多人的工作和生活方式,成为了世界上用…...
视频生成模型:构建虚拟世界的模拟器 [译]
原文:Video generation models as world simulators 我们致力于在视频数据上开展生成模型的大规模训练。具体来说,我们针对不同时长、分辨率和宽高比的视频及图像,联合训练了基于文本条件的扩散模型。我们采用了一种 Transformer 架构&#…...
MySQL数据库基础(十二):子查询(三步走)
文章目录 子查询(三步走) 一、子查询(嵌套查询)的介绍 二、子查询的使用 三、总结 子查询(三步走) 一、子查询(嵌套查询)的介绍 在一个 select 语句中,嵌入了另外一个 select …...
2-21算法习题总结
由于蓝桥杯的题,我不知道从怎么复制,就只能粘贴图片了 翻硬币 代码 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);String start sc.next();char[] starts start.toCharArray();String end sc…...
常见的排序算法整理
1.冒泡排序 1.1 冒泡排序普通版 每次冒泡过程都是从数列的第一个元素开始,然后依次和剩余的元素进行比较,若小于相邻元素,则交换两者位置,同时将较大元素作为下一个比较的基准元素,继续将该元素与其相邻的元素进行比…...
stm32——hal库学习笔记(定时器)
这里写目录标题 一、定时器概述(了解)1.1,软件定时原理1.2,定时器定时原理1.3,STM32定时器分类1.4,STM32定时器特性表1.5,STM32基本、通用、高级定时器的功能整体区别 二、基本定时器࿰…...
方法鉴权:基于 Spring Aop 的注解鉴权
在Spring框架中,可以使用面向切面编程(AOP)来实现注解鉴权。这通常涉及到定义一个切面(Aspect),该切面会在方法执行前进行拦截,并根据注解value值来决定是否允许执行该方法。 简单思路…...
多模态相关论文笔记
(cilp) Learning Transferable Visual Models From Natural Language Supervision 从自然语言监督中学习可迁移的视觉模型 openAI 2021年2月 48页 PDF CODE CLIP(Contrastive Language-Image Pre-Training)对比语言图像预训练模型 引言 它比ImageNet模型效果更好,…...
maven 打包命令
Maven是基于项目对象模型(POM project object model),可以通过一小段描述信息(配置)来管理项目的构建,报告和文档的软件项目管理工具。 Maven的核心功能便是合理叙述项目间的依赖关系,通俗点讲,就是通过po…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
