java中Class文件的文件格式

news2024/12/23 16:25:55

无关性的基石

计算机底层只能识别二进制,由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)的特殊形式,对于这几组特殊指令,它们省略掉了显式的操作数,不需要进行取 操作数的动作,因为实际上操作数就隐含在指令中。除了这点不同以外,它们的语义与 原生的通用指令是完全一致的

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

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

相关文章

SQL Server开启网络访问

目前工作中很少用到SQL Server了,最近需要测试几个表,需要搭建一个SQL Server数据库服务,这里做个总结吧。 安装这里就不做详细介绍了,本文只介绍如何开启SQL Server网络访问。 1、云服务器安全组设置 如果是搭建在云服务器上&a…

时序最佳入门代码|基于pytorch的LSTM天气预测及数据分析

前言 在本篇文章,我们基于pytorch框架,构造了LSTM模型进行天气预测,并对数据进行了可视化分析,非常值得入门学习。该数据集提供了2013年1月1日至2017年4月24日在印度德里市的数据。其中包含的4个参数是平均温度(meant…

【数字集成电路与系统设计】Chisel/Scala简介与Verilog介绍

目录 一、芯片前端设计开发背景知识 二、Verilog介绍 2.1 硬件设计一些重要概念 2.2 功能性仿真 2.3 简单的Verilog代码例子(4-bit的加法器) 三、Chisel简介 3.1 Chisel基本概念 3.2 Chisel代码展示 3.3 Chisel转成Verilog代码 四、Scala入…

数据清洗-缺失值填充-对XGBoost参数优化填充

目录 一、安装所需的python包二、采用XGboost算法进行缺失值填充2.1可直接运行代码2.2以某个缺失值数据进行实战2.2.1 代码运行过程截屏:2.2.2 填充后的数据截屏: 三、网格搜索(Grid Search)对 XGBoost 模型的超参数进行优化原理介…

Windows 上下载、编译 OpenCV 并配置系统环境变量的详细步骤

创作不易,您的打赏、关注、点赞、收藏和转发是我坚持下去的动力! 在 Windows 上下载并编译 OpenCV,然后配置系统环境变量的步骤如下: 1. 下载 OpenCV 打开 OpenCV 官方下载页面。找到最新的 Windows 版本,点击下载&…

初中生物--4.生物体的结构层次(二)

一、植物体的结构层次 1.绿色开花植物的六大器官 根、茎、叶、花、种子、果实 2.植物的组织 3.植物体的生长 植物体的生长是细胞分裂、生长和分化的综合结果。在植物体的生长过程中,细胞不断分裂产生新的细胞,新细胞不断生长使细胞体积增大&#xff…

数据结构 - 队列

一.队列的定义 1.队列的分类 队列根据存储结构可以分为 顺序队列 和 链式队列 2.队列的结构 ①.顺序队列 顺序队列的 front 指向队首元素的前一个下标 ②.链式队列 二.顺序队列的基本运算 0.顺序队列的结构体定义 typedef int data_t;typedef struct {data_t *data; …

stable diffusion 反推提示词插件 tagger 的安装,很详细

stable diffusion 反推提示词插件 tagger 的安装,很详细 一、前言二、下载1、方式一2、方式二 一、前言 最近想下载 stable diffusion 反推提示词插件 tagger ,也是好一番折腾,这里做个记录。 在安装之前确保能正常访问 github &#xff0c…

图像增强技术分析

图像增强是一种图像处理技术,旨在改善图像的视觉质量,使其更适合显示或进一步分析。这种技术可以应用于多种场景,包括医学成像、卫星图像、视频处理以及文本到图像生成模型等领域。图像增强的目标通常是提高图像的某些视觉特征,如…

[内网渗透]---msf基础-永恒之蓝-ms17-010

what Metasploit(通常简称为MSF)是一个开源的渗透测试框架,包含大量的已知漏洞利用模块,可以用来攻击目标系统并获取控制权。 how 实验环境:Kali、带有永恒之蓝漏洞的虚拟机且开启445端口(两个虚拟机同一子网) 1.信…

FPGA-Vivado-IP核-虚拟输入输出(VIO)

VIO IP核 背景介绍 Vivado中的VIO(Virtual Input/Output,虚拟输入/输出) IP核是一种用于调试和测试FPGA设计的IP核。当设计者通过JTAG接口与FPGA芯片连接时,在Vivado的Verilog代码中添加VIO IP核,就可以让设计者与FPG…

TCP 拥塞控制:一场网络数据的交通故事

从前有条“高速公路”,我们叫它互联网,而这条公路上的车辆,则是数据包。你可以把 TCP(传输控制协议)想象成一位交通警察,负责管理这些车辆的行驶速度,以防止交通堵塞——也就是网络拥塞。 第一…

08_Python数据类型_字典

Python的基础数据类型 数值类型:整数、浮点数、复数、布尔字符串容器类型:列表、元祖、字典、集合 字典 字典(Dictionary)是一种可变容器模型,它可以存储任意类型对象,其中每个对象都存储为一个键值对。…

3.4.3 __ipipe_init_early之初始化root domain

点击查看系列文章 》 Interrupt Pipeline系列文章大纲-CSDN博客 3.4.3 __ipipe_init_early之初始化root domain 如下图所示,红框里面的函数当前都是空的,本章还是分析蓝框中的代码片段。 第295行,变量ipd指向了ipipe_root即ipd代表root doma…

Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 内存分配和回收规则

文章目录 垃圾回收机制堆空间的基本结构内存分配和回收规则对象优先在 Eden 区分配分配担保机制 大对象直接进入老年代长期存活的对象进入老年代主要进行 GC 的区域部分收集 (Partial GC):Minor GCMajor/Old GCMixed GC 整堆收集(Full GC) 空…

K-means 算法的介绍与应用

目录 引言 K-means 算法的基本原理 表格总结:K-means 算法的主要步骤 K-means 算法的 MATLAB 实现 优化方法与改进 K-means 算法的应用领域 表格总结:K-means 算法的主要应用领域 结论 引言 K-means 算法是一种经典的基于距离的聚类算法&#xff…

中秋献礼!2024年中科院一区极光优化算法+分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测

中秋献礼!2024年中科院一区极光优化算法分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测 目录 中秋献礼!2024年中科院一区极光优化算法分解对比!VMD-PLO-Transformer-LSTM多变量时间序列光伏功率预测效果一览基本介…

人工智能和大模型的简介

文章目录 前言一、大模型简介二、大模型主要功能1、自然语言理解和生成2、文本总结和翻译3、文本分类和信息检索4、多模态处理三、大模型的技术特性1、深度学习架构2、大规模预训练3、自适应能力前言 随着技术的进步,人工智能(Artificial Intelligence, AI)和机器学习(Mac…

TryHackMe 第1天 | Introduction to Cyber Security

偶然之间了解到了TryHackMe这个网站,尝试跟着其中的学习路径进行学习,发现还是挺适合入门网络安全这一领域的。但是这个网站包含了很多内容,如果不用一些东西记录下来,那么很容易忘记,所以打算在此记录一下学习过程。 …

Linux——应用层自定义协议与序列化

目录 一应用层 1再谈 "协议" 2序列化与反序列化 3理解read,write,recv,send 4Udp vs Tcp 二网络版本计算器 三手写序列和反序列化 四进程间关系与守护进程 1进程组 1.1什么是进程组 1.2组长进程 2会话 2.1什么是会话 2.2会话下的前后台进程 3作业控…