java中Class文件的文件格式

无关性的基石

计算机底层只能识别二进制,由CPU直接处理二进制,在底层上面是操作系统,在操作系统上面就是虚拟机,java有一个口号,“一次编写,到处运行”这个不太可能在操作系统层面上实现,不同的操作系统肯定将会长期并存发展,所以这个理想只能在“应用层”实现。

在虚拟机中使用字节码,而所有的指令都会转成字节码,传递给虚拟机

Class类文件的结构

class文件是一串严格有序无分隔符无对齐符二进制流

class文件伪结构如下

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

在这里插入图片描述

魔数与 Class 文件的版本

每个Class文件的头四个字节称为魔数,他的作用是确定这个文件是否可以被虚拟机接受的Class文件

魔数的 4 个字节存储的是 Class 文件的版本号:第5和第 6个字节是次版本号,第 7 和第 8 个字节是主版本号

高版本的 JDK 能向下兼容以前版本的 Class 文件,但不能运行以后版本的 Class 文件

Class 文件格式采用一种类似于 C 语言结构体的伪结构来存 储数据,这种伪结构中只有两种数据类型:“无符号数”和“表”

  • 无符号数属于基本的数据类型,以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4 个字节 和 8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值
  • 表是由多个无符号数或者其他表作为数据项构成的复合数据类型

常量池

常量池可以比喻为 Class 文件里的资源仓库

在常量池的入口需要放置 一项 u2类型的数据,代表常量池容量计数值,这个从0开始不是1开始

常量池中主要存放两大类常量:字面量和符号引用

字面量就是java中的常量概念

符号引用属于编译原理方面的概念,主要包括下面的常量:

被模块导出或者开放的包

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符
  • 方法句柄和方法类型
  • 动态调用点和动态常量

在 Class 文件中不会保存各个方法、字段最终在内存中的 布局信息,这些字段、方法的符号引用不经过虚拟机在运行期转换的话是 无法得到真正的内存入口地址,也就无法直接被虚拟机使用的。当虚拟机做类加载时,将会从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。

常量池中每一项常量都是一个表,他有17个类表,表示17种不同类型的常量

17 类表都有一个共同的特点,表结构起始的第一位是个 u1 类型的标志位,代表着当前常量属于哪种常量类型。

这17个表每一个表的结构都不一样各自有着完全独立的数据结构,首位都是tag来标记数据类型,后面的根据不同的需要设计不同

访问标志

在常量池结束之后,紧接着的 2 个字节代表访问标志

这个标志用于识别一些类或者接口层次的访问信息,包括:这个Class 是类还是接口;是否定义为 public 类型;是否定义为 abstract 类型;如果是类的话,是否被声明为 final;等等

在这里插入图片描述

在这里插入图片描述

access_flags 中一共有 16 个标志位可以使用,当前只定义了其中 9 个,没有使用到的标志位要求一律为零

类索引、父类索引与接口索引集合

类索引和父类索引都是一个 u2 类型的数据,而接口索引集合是一组 u2 类型的数据的集合,Class 文件中由这三项数据来确定该类型的继承关系

接口索引集合,入口的第一项 u2 类型的数据为接口计数器,表示索引表的容量。

字段表集合

描述接口或者类中声明的变量

字段中可以包含各种各样的修饰符,这些修饰符可以使用标志位处理,但是字段叫什么名字,什么类型是无法确定的,只能使用常量池中的常量来描述

在这里插入图片描述

在Class文件中字段表集合的第一个U2类型数据为容量计数器,即记录字段表集合数量,之后就是上面的表中内容

方法表集合

方法表的结构如同字段表一样,依次包括访问标志 、名称索引、描述符索引 、属性表集合几项

方法的定义通过过访问标志、名称索引、描述符索引来表达清楚,方法中的代码内容会经过Javac 编译器编译成字节码指令之后,存放在方法属性表集合中一个名为“Code”的属性里面

方法表集合和字段表集合一样在具体描述表之前会有一个u2类型数据描述方法表集合的大小,代表这个集合中有几个方法

属性表集合

属性表在前面的讲解之中已经出现过数次,Class 文件、字段表、方法表都可以携带自己的属性表集合,以描述某些场景专有的信息。

只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,Java 虚拟机运行时会忽略掉它不认识的属性。

对于每一个属性,它的名称都要从常量池中引用一个 CONSTANT_Utf8_info 类型的 常量来表示,而属性值的结构则是完全自定义的,只需要通过一个 u4 的长度属性去说 明属性值所占用的位数即可

在这里插入图片描述

总结

在这里插入图片描述

还是这张图

一个Class文件首先是四个字节的一个魔数用来表示是否可以被虚拟机接收,然后是版本号,次级版本号,然后是常量池中存储我们需要使用的数据,不光是编译前的数据还包括编译时的数据比如接口限定名等,在这里首先会使用一个u2的大小记录常量池大小然后在根据不同记录常量,在常量记录完毕之后是访问标识是一些类的访问信息,然后是类索引父类索引等,接下来是接口索引记录接口数量,然后会有一个接口池记录接口信息,接口记录完毕后面就是字段表,方法表,属性表的记录,这些表都有一个计数器记录大小

  • 魔数
  • 版本,次版本
  • 访问标志
  • 常量池
  • 类,父类,接口索引,
  • 字段表,方法表,属性表

字节码指令简介

Java 虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需的参数(称为操作数, Operand)构成。

指令集因为他的操作码只有一个数字所以他的操作码指令数不能超过256条,这样它在处理一些超过一个字节的数据时需要从字节中重建出具体的数据结构,他会损失掉一些性能,好处在于放弃了操作数长度对齐,省略掉大量的填充和间隔符号

字节码和数据类型

在java的指令集中,大部分指令都有包含其操作对应的数据类型信息,

对于大部分与数据类型相关的字节码指令,它们的**操作码助记符**中都有特殊的字符来表明专门为哪种数据类型服务:

  • i 代表对 int 类型的数据操作,
  • l 代表 long,s 代表 short,
  • b 代表 byte,c 代表 char,
  • f 代表 float,d 代表 double,
  • a 代表 reference。

也有一些指令的助记符没有明确指明操作类型的字母

因为操作集只有一个字节所以它没有设计所有的数据类型的操作码,Java 虚拟机的指令集对于特定的操作只提供了有限的类型相关指令去支持它,在处理的时候如果发现某一个数据类型没有对应的指令集会对其进行相关的扩展比如编译器会在编译期或运行期将 byte 和 short 类型的 数据带符号扩展为相应的 int 类型数据

加载和存储指令

加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输,这类指令包括:

  • 将一个局部变量加载到操作栈:iload、iload_、lload、lload_、fload、 fload_、dload、 dload_、aload、aload_
  • 将一个数值从操作数栈存储到局部变量表:istore、istore_、lstore、 lstore_、fstore、 fstore_、dstore、dstore_、astore、astore_
  • 将一个常量加载到操作数栈:bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、 iconst_m1、 iconst_、lconst_、fconst_、dconst_
  • 扩充局部变量表的访问索引的指令:wide

指令助记符中,有一部分是以尖括号结尾的(例如 iload_),这些 指令助记符实际上代表了一组指令(例如 iload_,它代表了 iload_0、iload_1、 iload_2 和 iload_3 这几条指令)。这几组指令都是某个带有一个操作数的通用指令(例如 iload)的特殊形式,对于这几组特殊指令,它们省略掉了显式的操作数,不需要进行取 操作数的动作,因为实际上操作数就隐含在指令中。除了这点不同以外,它们的语义与 原生的通用指令是完全一致的

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

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

相关文章

俄罗斯方块——C语言实践(Dev-Cpp)

目录 1、创建项目(尽量不使用中文路径) 2、项目复制 3、项目配置 ​1、调整编译器 2、在配置窗口选择参数标签 3、添加头文件路径和库文件路径 4、代码实现 4.1、main.c 4.2、draw.h 4.3、draw.c 4.4、shape.h 4.5、shape.c 4.6、board.h 4.7、board.c 4.8、cont…

Vue.js入门系列(二十九):深入理解编程式路由导航、路由组件缓存与路由守卫

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] &#x1f4f1…

解锁编程潜力,从掌握GitHub开始

目录: 一、搜索开源项目 1、什么是Git 2、Github常用词含义 3、一个完整的项目界面 4、使用Github搜索项目 1)in关键词 2)star或fork数量去查找 3)awesome加强搜索 二、访问速度慢的解决 1、使用网易UU加速器 2、使用…

Visual Studio(vs)下载安装C/C++运行环境配置和基本使用注意事项

基本安装 点击跳转到vs官网点击箭头所指的按钮进行下载双击运行刚才下载好的下载器点击继续勾选“使用C的桌面开发”和“Visual Studio扩展开发”点击“安装位置”,对vs的安装位置进行更改。你可以跟我一样只选择D盘或者其他你空闲的盘,然后将默认的路径…

响应式CSS 媒体查询——WEB开发系列39

CSS媒体查询(Media Queries)是响应式设计中的核心技术之一,帮助我们在不同设备上展示不同的样式。通过媒体查询,开发者可以检测用户设备的特性,如屏幕宽度、高度、分辨率、方向等,针对性地调整网页布局。 一…

架构师知识梳理(七):软件工程-工程管理与开发模型

软件工程概述 软件开发生命周期 软件定义时期:包括可行性研究和详细需求分析过程,任务是确定软件开发工程必须完成的总目标,具体可分成问题定义、可行性研究、需求分析等。软件开发时期:就是软件的设计与实现,可分成…

气压测试实验(用IIC)

I2C: 如果没有I2c这类总线,连接方法可能会如下图: 单片机所有的通讯协议,无非是建立在引脚(高低电平的变换高低电平持续的时间)这二者的组合上,i2c 多了一个clock线,负责为数据传输打节拍。 (i2…

如何删除git提交记录

今天在提交github时,不小心提交了敏感信息, 不要问我提交了啥,问就是不知道 查了下资料,终于找到简单粗暴的方式来删除提交记录。方法如下 git reset --soft HEAD~i i代表要恢复到多少次提交前的状态,如指定i 2&…

一文读懂:如何将广告融入大型语言模型(LLM)输出

本文是我翻译过来的,讨论了在线广告行业的现状以及如何将大型语言模型(LLM)应用于在线广告。 原文请参见”阅读原文“。 在2024年,预计全球媒体广告支出的69%将流向数字广告市场。这个数字预计到2029年将增长到79%。在Meta的2024…

微服务——网关路由(Spring Cloud Gateway)

网关路由 1.什么是网关 网关又称网间连接器、协议转换器,是在网络层以上实现网络互连的复杂设备,主要用于两个高层协议不同的网络之间的互连。网关就是网络的关口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由…

Kafka 基础与架构理解

目录 前言 Kafka 基础概念 消息队列简介:Kafka 与传统消息队列(如 RabbitMQ、ActiveMQ)的对比 Kafka 的组件 Kafka 的工作原理:消息的生产、分发、消费流程 Kafka 系统架构 Kafka 的分布式架构设计 Leader-Follower 机制与…

安卓玩机工具-----无需root权限 卸载 禁用 删除当前机型app应用 ADB玩机工具

ADB玩机工具 ADB AppControl是很实用的安卓手机应用管理工具,无需root权限,通过usb连接电脑后,可以很方便的进行应用程序安装与卸载,还支持提取手机应用apk文件到电脑上,此外还有手机系统垃圾清理、上传文件等…

VMware Workstation Player虚拟机Ubuntu启用Windows共享目录

1、新建共享目录 2、安装并启用vmtools、fuse sudo apt update sudo apt install open-vm-tools open-vm-tools-desktop sudo apt install fuse sudo systemctl start open-vm-tools sudo systemctl enable open-vm-tools 3、命令挂载 sudo vmhgfs-fuse .host:/SharedFold…

初学Linux(学习笔记)

初学Linux(学习笔记) 前言 本文跳过了Linux前期的环境准备,直接从知识点和指令开始。 知识点: 1.目录文件夹(Windows) 2.文件内容属性 3.在Windows当中区分文件类型是通过后缀,而Linux是通过…

leaflet【十】实时增加轨迹点轨迹回放效果实现

实时轨迹回放 在前面有用leaflet-trackplayer实现了一个轨迹回放的效果,单击前往:轨迹回放效果&控制台控制轨迹运动效果 这篇文章主要是实现一下实时增加轨迹点,不改变原来运行轨迹和速度。这里是简易做了一个demo效果,大概…

vue3透传、注入

属性透传 传递给子组件时,没有被子组件消费的属性或事件,常见的如id、class 注意1 1.class、style是合并的,style中如果出现重复的样式,以透传属性为准2.id属性是以透传属性为准,其他情况透传属性名相同&#xff0c…

【AI视频】复刻抖音爆款AI数字人作品初体验

博客主页: [小ᶻZ࿆] 本文专栏: AI视频 | AI数字人 文章目录 💯前言💯抖音上的爆火AI数字人视频💯注册HeyGen账号💯复刻抖音爆款AI数字人💯最终生成效果💯小结 对比原视频效果:…

【算法篇】哈希类(笔记)

目录 一、常见的三种哈希结构 二、LeetCode 练习 1. 有效的字母异位词 2. 两个数组的交集 3. 快乐数 4. 两数之和 5. 四数相加II 6. 赎金信 7. 三数之和 8. 四数之和 一、常见的三种哈希结构 当想使用哈希法来解决问题的时候,一般会选择如下三种数据…

Java--String类

前言: 在之前的学习中,学习了和了解了一些类的基本使用,例如object类等等,但是我们用String这个引用或者说这个类其实我们已经用了好久,只不过没有具体分析过! 对于String类,它可以引用一个字符…

JavaScript web API part3

web API DOM 日期对象 > 得到当前系统的时间 new这个操作就是实例化 语法 const date new Date() or const date new Date(2004-11-3 08:00:00) 可以指定时间 > 可应用于通过系统时间和指定时间实现倒计时的操作 //得到当前时间const date new Date()console.lo…