没有合适的资源?快使用搜索试试~ 我知道了~
笔记,3、JVM的执行子系统2
资源详情
资源评论
资源推荐
Class 类文件结构
Java 跨平台的基础
各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(ByteCode)是构
成平台无关性的基石,也是语言无关性的基础。Java 虚拟机不和包括 Java 在内的任何语言
绑定,它只与“Class 文件”这种特定的二进制文件格式所关联,Class 文件中包含了 Java 虚
拟机指令集和符号表以及若干其他辅助信息。
Class 类的本质
任何一个 Class 文件都对应着唯一一个类或接口的定义信息,但反过来说,Class 文件实际上
它并不一定以磁盘文件的形式存在。
Class 文件是一组以 8 位字节为基础单位的二进制流。
Class 文件格式
各个数据项目严格按照顺序紧凑地排列在 Class 文件之中,中间没有添加任何分隔符,这使
得整个 Class 文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。
Class 文件格式采用一种类似于 C 语言结构体的伪结构来存储数据,这种伪结构中只有两种
数据类型:无符号数和表。
无符号数属于基本的数据类型,以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4 个
字节和 8 个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8
编码构成字符串值。
表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以
“_info”结尾。表用于描述有层次关系的复合结构的数据,整个 Class 文件本质上就是一张
表。
Class 文件格式详解
Class 的结构不像 XML 等描述语言,由于它没有任何分隔符号,所以在其中的数据项,无论
是顺序还是数量,都是被严格限定的,哪个字节代表什么含义,长度是多少,先后顺序如何,
都不允许改变。
按顺序包括:
魔数与 Class 文件的版本
每个 Class 文件的头 4 个字节称为魔数(Magic Number),它的唯一作用是确定这个文件是
否为一个能被虚拟机接受的 Class 文件。使用魔数而不是扩展名来进行识别主要是基于安全
方面的考虑,因为文件扩展名可以随意地改动。文件格式的制定者可以自由地选择魔数值,
只要这个魔数值还没有被广泛采用过同时又不会引起混淆即可。
紧接着魔数的 4 个字节存储的是 Class 文件的版本号:第 5 和第 6 个字节是次版本号
(MinorVersion),第 7 和第 8 个字节是主版本号(Major Version)。Java 的版本号是从 45 开
始的,JDK 1.1 之后的每个 JDK 大版本发布主版本号向上加 1 高版本的 JDK 能向下兼容以前
版本的 Class 文件,但不能运行以后版本的 Class 文件,即使文件格式并未发生任何变化,虚
拟机也必须拒绝执行超过其版本号的 Class 文件。
常量池
常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项 u2 类型的数据,代表
常量池容量计数值(constant_pool_count)。与 Java 中语言习惯不一样的是,这个容量计数
是从 1 而不是 0 开始的
常量池中主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。
字面量比较接近于 Java 语言层面的常量概念,如文本字符串、声明为 final 的常量值等。
而符号引用则属于编译原理方面的概念,包括了下面三类常量:
类和接口的全限定名(Fully Qualified Name)、字段的名称和描述符(Descriptor)、方法的名
称和描述符
访问标志
用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口;是否定义为 public
类型;是否定义为 abstract 类型;如果是类的话,是否被声明为 final 等
类索引、父类索引与接口索引集合
这三项数据来确定这个类的继承关系。类索引用于确定这个类的全限定名,父类索引用于确
定这个类的父类的全限定名。由于 Java 语言不允许多重继承,所以父类索引只有一个,除
了 java.lang.Object 之外,所有的 Java 类都有父类,因此除了 java.lang.Object 外,所有 Java
类的父类索引都不为 0。接口索引集合就用来描述这个类实现了哪些接口,这些被实现的接
口将按 implements 语句(如果这个类本身是一个接口,则应当是 extends 语句)后的接口顺
序从左到右排列在接口索引集合中
字段表集合
描述接口或者类中声明的变量。字段(field)包括类级变量以及实例级变量。
而字段叫什么名字、字段被定义为什么数据类型,这些都是无法固定的,只能引用常量池中
的常量来描述。
字段表集合中不会列出从超类或者父接口中继承而来的字段,但有可能列出原本 Java 代码
之中不存在的字段,譬如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实
例的字段。
方法表集合
描述了方法的定义,但是方法里的 Java 代码,经过编译器编译成字节码指令后,存放在属
性表集合中的方法属性表集合中一个名为“Code”的属性里面。
与字段表集合相类似的,如果父类方法在子类中没有被重写(Override),方法表集合中就
不会出现来自父类的方法信息。但同样的,有可能会出现由编译器自动添加的方法,最典型
的便是类构造器“<clinit>”方法和实例构造器“<init>”
属性表集合
存储 Class 文件、字段表、方法表都自己的属性表集合,以用于描述某些场景专
有的信息。如方法的代码就存储在 Code 属性表中。
字节码指令
Java 虚拟机的指令由一个字节长度的、代表着某种特定操作含义的数字(称为操作码,Opcode)
以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。
由于限制了 Java 虚拟机操作码的长度为一个字节(即 0~255),这意味着指令集的操作码总
数不可能超过 256 条。
大多数的指令都包含了其操作所对应的数据类型信息。例如:
iload 指令用于从局部变量表中加载 int 型的数据到操作数栈中,而 fload 指令加载的则是 float
类型的数据。
大部分的指令都没有支持整数类型 byte、char 和 short,甚至没有任何指令支持 boolean 类
型。大多数对于 boolean、byte、short 和 char 类型数据的操作,实际上都是使用相应的 int
类型作为运算类型
阅读字节码作为了解 Java 虚拟机的基础技能,请熟练掌握。请熟悉并掌握常见指令即可。
加载和存储指令
用于将数据在栈帧中的局部变量表和操作数栈之间来回传输,这类指令包括如下内容。
将一个局部变量加载到操作栈:iload、iload_<n>、lload、lload_<n>、fload、fload_<n
>、dload、dload_<n>、aload、aload_<n>。
将一个数值从操作数栈存储到局部变量表:istore、istore_<n>、lstore、lstore_<n>、
fstore、fstore_<n>、dstore、dstore_<n>、astore、astore_<n>。
将 一 个 常 量 加 载 到 操 作 数 栈 : bipush 、 sipush 、 ldc 、 ldc_w 、 ldc2_w 、 aconst_null 、
iconst_m1、iconst_<i>、lconst_<l>、fconst_<f>、dconst_<d>。
扩充局部变量表的访问索引的指令:wide。
剩余11页未读,继续阅读
陈游泳
- 粉丝: 30
- 资源: 302
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 一个chm格式的 SQL 函数手册-SQL语言手册文档
- 计算当前月份的天数和剩余天数
- 基于ARM的指令调度和延迟分支
- 基于Vue和TypeScript的极简聊天应用设计源码 - HasChat
- 基于Vue2全家桶和Zcool数据的图片收集网站设计源码 - cool-picture
- 基于C和C++的二维绘制工具设计源码 - DrawPro
- Object.defineProperty 的 IE 补丁object-defineproperty-ie-master.zip
- 整卷预览.mhtml
- MySQL是一种广泛使用的开源关系型数据库管理系统,它提供了丰富的SQL语句用于数据库的创建、查询、更新和管理 以下是一些常见的
- MySQL是一种广泛使用的开源关系型数据库管理系统,它提供了丰富的SQL语句用于数据库的创建、查询、更新和管理 以下是一些常见
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0