Java 类文件结构

Java 诞生之时有句著名的宣传口号“Write Once, Run Anywhere.”。但是,Java 语言本身不具备跨平台的能力,而是 JVM 提供了跨平台的能力。
事实上,不仅 Java 可以运行在 JVM 上,现在已经出现了其他的语言可以运行在 JVM 上,如 Clojure、Scala 等。也就是说,JVM 并不和包括 Java 在内的任何语言绑定,只与“Class 文件”这种特定的二进制文件格式相关联,Class 文件包含了 Java 虚拟机指令集和符号表以及若干其他辅助信息。这篇文章就主要介绍存储字节码的 Class 文件。
任何一个 Class 文件都对应着唯一一个类或接口的定义信息,但是,类或接口的定义信息并非一定要在类文件中。
Class 文件是一组以 8 位为基础单位的字节流(二进制流),每个数据项严格按照顺序节凑排列在 Class 文件中,中间没有任何分隔符。多字节的数据项按照大端序存储(高字节存储在最低地址位)。
基本概念
JVM 规范规定,Class 文件采用一种类似于 C 语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。
- 无符号数是基本的数据类型,以 u1、u2、u3、u4 分别代表 1 个字节、2 个字节、3 个字节、 4 个字节。无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8 编码构成字符串值。
- 表由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯地以"_info"结尾。表用于描述有层次关系的复合结构的数据,这个 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 文件就对应这样一个 ClassFile 的结构。
无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式,这是称这一序列连续的某一个类型的数据为某一类型集合。如 fields_count 来描述 field_info 的数量(这些 field_info 就构成一个集合)。
ClassFile 中每个项目解释如下表(attributes_count 和 attributes[] 比较复杂,这里暂不介绍,我会在文章末尾提供参考资料):
| item | 含义 |
|---|---|
| magic | 魔数,它的唯一作用时确定这个文件能否为一个能被虚拟机接受的 Class 文件。许多文件标准中都使用魔数来进行身份标识。Class 文件的魔数值为:0xCAFEBABE |
| minor_version | 这个类文件的次版本号。 |
| major_version | 这个类文件的主版本号。 |
| constant_pool_count | 常量池容器计数值,等于常量池(constant_pool) 中实体数量加 1 。常量池的索引只有在比零大,比该值小才认为是有效的。 |
| constant_pool[] | 常量池中的结构表示字符串常量、类名字、接口名字、字段(field name)、其他常量(指向 ClassFile 中的其他结构、子结构)。 |
| access_flag | 访问标志。用于识别一些类或接口层次的访问信息,包括:这个 Class 是类还是接口;是否定义为 public;是否定义为 abstract 类型;如果是类的话,是否被声明为 final 等。 |
| this_class | 用于确定这个类的全限定名。 |
| super_class | 用于确定这个类的父类的全限定名。 |
| interfaces_count | 用于标识类实现了几个接口。 |
| interfaces[] | 类实现了哪些接口,按 implements 后的顺序显示在这个集合中。 |
| fields_count | 用于描述接口或者类中声明的变量的数量,字段包括类级变量以及实例级变量。 |
| fields[] | 用于描述接口或者类中声明的变量,字段包括类级变量以及实例级变量。描述信息包括:字段的作用域(public、private、protected)、实例变量还是类变量(static)、可变性(final)、并发可见性(volatile)、字段数据类型、字段名称、可否被序列化。除字段数据类型、字段名称需要引用常量池中常量来描述外,其余均用标志位来表示。 |
| methods_count | 接口或类中方法的数量。 |
| methods[] | 描述接口或类中的方法。 |
Class 的文件格式大体上就是这样,还有大量细节没有描述,如常量池中各种常量项的结构、访问标志具体值与名称、字段描述符、方法描述符、属性表等。由于这些都是规范,这里不再写了,想更近一步了解的话,可以阅读 Java 虚拟机规范。
参考:
The Java Virtual Machine Specification, Java SE 8 Edition
《深入理解Java虚拟机》
Java 类文件结构的更多相关文章
- 《深入理解java虚拟机》笔记——简析java类文件结构
一直不太搞得明确jvm究竟是如何进行类载入的,在看资料的过程中迷迷糊糊.在理解类载入之前,首先看看java的类文件结构究竟是如何的,都包含了哪些内容. 最直接的參考当然是官方文档:The Java® ...
- 不知道Java类文件结构的同学,看这篇文章就够了
一.前言 代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步.经过多年的发展,目前的计算机仍然只能识别0和1,但是由于近10年内虚拟机以及大量建立在虚拟机之上的程 ...
- Java类文件结构详解
概述: Class文件结构是了解虚拟机的重要基础之一,如果想深入的了解虚拟机,Class文件结构是不能不了解的.Class文件是一组以8位字节为基础单位的二进制流,各项数据项目严格按照顺序紧凑地排列在 ...
- java类文件结构笔记
注:新的博客地址 - https://zhengw-tech.com/archives/ 我们都知道java实现跨平台靠的是虚拟机技术,将源文件编译成与操作系统无关的,只有虚拟机能识别并执行的字节码文 ...
- Java类文件结构
一.概述 实现语言无关性的基础是虚拟机和字节码存储格式.Java虚拟机不和包括Java在内的任何语言绑定,只与"Class文件"这种特定的二进制文件所关联,Class文件中包含了J ...
- Java类文件结构及javac的ClassReader类解读
首先来看一下ClassFile,类注释如下: A JVM class file. Generic Java classfiles have one additional attribute for c ...
- Java虚拟机,类文件结构深度解析
Java类文件结构 Java虚拟机不和包括Java在内的任何语言绑定,只与 "Class文件" 这种特定的二进制文件所关联, Class文件中包含了Java虚拟机指令集合符号表以及 ...
- JVM学习笔记(三):类文件结构
代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步. 实现语言无关性的基础是虚拟机和字节码存储格式.Java虚拟机不和包括Java在内的任何语言绑定,只与&quo ...
- JVM类文件结构
作为一名Java后台开发的程序员, 深入理解JVM, 重要性不言而喻, 这篇文章主要是记录JVM类文件结构相关知识. 2. 实例 这部分比较抽象, 所以以实例的形式来学习. 这部分作为资料, 以便后面 ...
随机推荐
- SpringBoot application.yml logback.xml,多环境配置,支持 java -jar --spring.profiles.active
趁今天有时间整理了一下 启动命令为 //开发环境 java -jar app.jar --spring.profiles.active=dev--server.port=8060 //测试环境 jav ...
- QT creator 其他资源(image)的添加以及简单利用
QT creator 添加一些资源文件 :https://www.cnblogs.com/cszlg/p/3234786.html(转自园子) 补充: 补充:如果要给生成的exe可执行文件更换一个自 ...
- java复习
局部变量的作用域只在方法内部有效,在方法外无效 用类型作为形参传递会改变实参的值,但是String是特殊的引用类型,作为形参传递不会影响实参的值. HashMap非线程安全,在多个线程访问Hashta ...
- Day5模块-shutil模块
参考博客:http://www.cnblogs.com/wupeiqi/articles/4963027.html shutil模块是高级的文件.文件夹.压缩处理的模块.比如文件的copy.压缩等. ...
- Redis实现数据库读写分离
Redis简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工作 ...
- mysql打不开表问题解决方案
做开发时候某一表怎么也打不开,数据也不多,网上查了按下面这篇文章完美解决,但是要记得用root登录mysql: 记一次MySQL中Waiting for table metadata lock的解决方 ...
- PCI和PCIE插槽有什么区别?
PCI是Peripheral Component Interconnect(外设部件互连标准)的缩写,它是目前个人电脑中使用最为广泛的接口,几乎所有的主板产品上都带有这种插槽.PCI插槽也是主板带有最 ...
- 一句python,一句R︱python中的字符串操作、中文乱码
先学了R,最近刚刚上手python,所以想着将python和R结合起来互相对比来更好理解python.最好就是一句python,对应写一句R. pandas可谓如雷贯耳,数据处理神器. 以下符号: = ...
- python3写入csv多一个空行
今天用python3 写入csv 总是多一个空行,查阅python3文档,发现有一个参数可以设置.特此记录一下. with open('file.csv','a',newline='') as csv ...
- 修改或隐藏Nginx的版本号
隐藏版本号 隐藏nginx的版本号很简单,nginx的HttpCoreModule提供了一条叫做server_tokens指令,我这要将这条指令设置为“server_tokens off”就可以了. ...