当前位置: 首页 > news >正文

Class类文件结构概述

参考文献:周志明《深入理解Java虚拟机》第二版

关于Class文件

class 文件应该是所有 Java 程序员都必定知道的文件,因为我们的 Java 源代码经过 javac 编译以后就会得到这个 class 文件。但是,它虽然与 Java 关系密切可它并不仅仅属于 Java,因为它属于虚拟机,虚拟机能够执行的就是 class 文件。所以我们 Java 虚拟机,其实就根本不认识 Java。
不过,也正是因为 JVM 只认识这个 class 文件,才使得 Java 有了最NB的一大特色:“一次编译,到处运行”。JVM 无论在哪,只需要带着这个 class 文件就能跑代码。但是,其实这种平台无关性也并不是最NB的地方,因为 JVM 的设计者们想要实现的最终目标是 语言无关性 ,就是让其他的语言也能跑在 JVM 上,真正的实现“大一统”,比如现在一些语言就推出了 JVM 版本,例:Jython(Python), JRuby(Ruby), Rhino(JavaScript),Groovy 等。所以 Java 程序员们,不要担心 Java 会被替代,好好学 JVM ,以后一定前途无量啊!

好了,言归正传


Class文件结构概述

因为 class 文件结构这里比较繁琐,而且大部分是固定的数据结构,所以我只简单的整理一下,详细的信息请从参考资料查阅

class 文件是一组以 8 位字节为基础单位的二进制流,各个数据项目按照顺序紧凑地排列在 class 文件中,中间没有添加任何分隔符,这使得整个 class 文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。当遇到需要占用 8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个 8 位字节进行存储

class 文件只有两种数据类型:无符号数,表
无符号数是基本类型,以 u1, u2, u4, u8 分别代表 1 个字节,2 个字节,4 个字节, 8 个字节的无符号数
表是由多个无符号数或其他表作为数据项构成的复合数据类型,所有表都以“_info”结尾,甚至可以说整个 class 文件就是一张表
这里写图片描述
这张表就是 class 文件中包含的所有数据项
我们接下来逐一进行介绍

魔数(magic number)与版本(version)

从表中可以看出,class 文件的第一个数据项是一个 u4 类型,占 4 个字节的 魔数,它的唯一作用是用来确定该 class 文件是否可以被虚拟机接受,这个作用就相当于文件的后缀名,.txt,.jpg,.gif,.mp4等等,那为什么不用后缀名呢?因为这样隐式的更加安全,class 文件的 magic number 很有意思,它的值为:0xCAFFBABE (咖啡宝贝),这个名字在 Java 还叫 Oak 的时候就确定了缘由是开发人员喜欢喝咖啡,这也是 Java 的 logo 的由来

接着后面是 2 个字节的次版本号(minor version)2 个字节的主版本号(major version)


常量池(constant_pool)

再下来是就是 class 文件的资源仓库 常量池 了,它是 class 文件结构中与其他项目关联最多的数据类型,也是占用空间最大的数据项之一
因为常量池的大小不固定,它由程序决定,所以在它之前是一个 u2 的常量池容量计数值(constant_pool_count)后面的数据项都是一样,所有 _info 类型的数据项大小都是由程序决定,所以前面都有一个计数值
这里需要注意的是,constant_pool_count 是从 1 开始计数的,空出 0 是为了表示“不引用任何一个常量池项目”

常量池中主要存放两大类常量:字面量符号引用
字面量:文本字符串,final常量等
符号引用:类和接口全限定名,字段的名称和描述,方法的名称和描述

常量池中每一项常量都是一个表,目前有这 14 种
这里写图片描述
这其中每一个类型的表都还有自己的结构
例:
这里写图片描述
这里写图片描述
所以这也是常量池占存大的原因


访问标志(access_flags)

常量池结束后,就是 u2 的访问标志它用来识别一些类或接口层次的访问信息
例:判断是 class 还是 interface,标记修饰符 public, protected, abstract等
这里写图片描述

类索引(this_class),父索引(super_class),接口索引集合(interfaces)

类索引为 u2,父索引为 u2,接口索引集合为一个 u2 集合(前面还有一个 u2 的计数器 interface_count)
根据 Java 语言的规则,除了 java.lang.Object 之外,其他所有类的父类均不为 0
这里写图片描述
这里写图片描述


字段表集合(fields)

字段表用来描述接口或者类中声明的变量字段包括类级变量和实例级变量,但不包括在方法内部声明的局部变量。
这里写图片描述
access_flags 就是用来标记字段作用域,修饰符等信息
这里写图片描述
注意,从表中我们可以看出,这些字段标记是严格按照 Java 规则制定的,例:
private int m 的 access_flags 就为:0002
public static int m 的 access_flags 就为:0001(public)+ 0008(static)= 0009
protected final double m 的 access_flags 就为:0004(protected)+ 0010(final)= 0014
然后是 name_index 和 descriptor_index ,分别代表字段的简单名称和字段和方法的描述符
描述符规则:基本类型用字母表示,数组用“[”表示,方法参数用“()”括起来
这里写图片描述
例:
void inc() 描述符为:“()V”
java.lang.String.toString() 描述符为:“()Ljava/lang/String;”
int indexOf(char[]source,int sourceOffset,int sourceCount,char[]target,int targetOffset,int targetCount,int fromIndex) 描述符为:“([CII[CIII)I”

字段表集合中不会列出从超类或者父类接口中继承的字段,但可能列出原本 Java 代码中不存在的字段,如,在内部类中添加指向外部类实例的字段(保持外部访问性)
对 Java 来说,无论描述符如何,字段都不能重名
对字节码来讲,如果字段描述符不同,重名也是合法的


方法表集合(methods)

这部分的结构与字段表几乎相同
这里写图片描述

这里针对字段与方法的不同,在访问标志上有修改

这里写图片描述

仔细查看方法表结构,你会发现,方法中的代码并不在其中,因为,方法里的 Java 代码,经过编译器编译成字节码指令后,存放在方法属性表集合(attributes)中一个名为“Code”的属性里


属性表集合(attributes)

class 文件对于这一数据项的要求比较宽松,它不必有严格的顺序,并且只要不与已有的属性名重复,任何人实现的编译器都可以向属性表写入自己定义的属性信息(支持用户自主扩展)
在最新的《Java虚拟机规范(Java SE 7)》中有 21 项预定义的属性,
例:
这里写图片描述
完整表格请查阅参考资料

所有预定义或是自定义的属性都应该符合属性表结构
这里写图片描述
这其中的每一个属性都有自己的结构表,里面包含了其所定义的一些数据

相关文章:

  • Spring MVC-集成(Integration)-生成JSON示例(转载实践)
  • Spring MVC-集成(Integration)-集成LOG4J示例(转载实践)
  • WebSocket使用
  • CCF201703试题
  • 2017-09-12 前端日报
  • 看似“触手可及”的Oculus离我们有多远?
  • 【小工具】python 在服务器上临时启用一个端口
  • ARM-Linux中断系统
  • 马云:不利用互联网技术,比缺电更可怕
  • 微信JS-SDK实现上传图片功能
  • ES6--对象的扩展
  • 毕业随想(转载)
  • 7.06 生成累计和
  • 算法与数据结构(七) 图论
  • 中国人民公安大学(PPSUC) 网络对抗技术作业
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • cookie和session
  • C语言笔记(第一章:C语言编程)
  • Date型的使用
  • Docker入门(二) - Dockerfile
  • Git的一些常用操作
  • JavaScript中的对象个人分享
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • js写一个简单的选项卡
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • Meteor的表单提交:Form
  • MySQL的数据类型
  • ng6--错误信息小结(持续更新)
  • React系列之 Redux 架构模式
  • ViewService——一种保证客户端与服务端同步的方法
  • 编写符合Python风格的对象
  • 订阅Forge Viewer所有的事件
  • 聚簇索引和非聚簇索引
  • 以太坊客户端Geth命令参数详解
  • mysql面试题分组并合并列
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (一)基于IDEA的JAVA基础1
  • (转)fock函数详解
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转)为C# Windows服务添加安装程序
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • .bat文件调用java类的main方法
  • .NET 3.0 Framework已经被添加到WindowUpdate
  • .NET Micro Framework 4.2 beta 源码探析
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .NET Standard、.NET Framework 、.NET Core三者的关系与区别?
  • .NET 常见的偏门问题
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .NET的微型Web框架 Nancy