Java类文件的基本结构

简介:

为旅行而生
  Java类文件(.class文件)是一个为已编译Java程序仔细定义的格式。Java源代码被编译成能够被任何JVM加载和执行的类文件。在被JVM加载之前,类文件可能是由网络传输而来。
  类文件是独立于底层平台的,所以适用于更多的地方。它们由简洁的JVM字节码组成,这样就能轻装上阵。类文件常常被压缩,以极快的速度通过网络,到达世界各地的JVM。
  类文件里有什么?
  Java类文件包含JVM需要知道的关于一个Java类或接口的一切。按照它们的出现次序,主要的部分有:魔法数(magic),版本号(version),常量池(constant pool),访问标示符区(access flags),当前类区(this class),超类区(super class),父接口区(interfaces),字段区(fields),方法列表区(methods),属性区(attributes)。
  保存在类文件中的信息经常在长度上有变化,所以信息的实际长度在被加载之前不能被预测。例如,在方法区里的方法数目,类与类之间是不相同的,这取决于源代码中定义的方法个数。类文件中,这些信息的实际大小或长度,被安排在信息内容之前。这样,当类文件被JVM加载时,可变信息的长度首先被读取。一旦JVM知道信息的大小,它就能正确的读取实际的信息内容。
  类文件中,不同的相邻信息之间通常没有空白或填充字符;一切都以字节(byte)边界对齐。这使得类文件很小,适合网络传输。
  为了让JVM在加载类文件时,知道需要什么信息以及从哪里可以取得所需信息,类文件的各个组成部分的次序是严格定义的。例如,每个JVM都知道类文件的前8个字节由魔法数和版本号组成,常量池从第9个字节开始,访问标示符区紧跟在常量池后面。但是,因为常量池的长度是可变的,在读取完常量池之前,JVM是不知道访问标示符区具体从什么地方开始。一旦读取完常量池,JVM就知道接下来的2个字节就是访问标示符区。
  魔法数(Magic)和版本号(Version)
  每个类文件的开始4个字节都是0xCAFEBABE。这个神奇的数字让Java类文件更容易识别,因为类文件以外的文件几乎不可能也以这四个相同的字节开头。之所以称之为魔法数,是因为它可以被文件格式设计者们从帽子里拉出来(??)。对它仅有的要求是,不能被现实已有的文件格式占用。根据最初Java团队主要成员之一的Patrick Naughton所说,远在“Java”被当作Java语言的名称之前,这个神奇的数字就已经被选好了。我们当时在寻找一个有趣,独特并且很容易记住的数字。0xCAFEBABE作为漂亮的Peet’s Coffee的咖啡师的代称,能预示未来Java语言的名字,这完全是一个巧合。
  类文件接下来的4个字节包含了大版本号(major version)和小版本号(minor version)。这些数字标识了特定类文件使用的类文件格式,让JVM可以验证类文件是否可以被载入。每个JVM都有一个它能载入的最大版本号,拒绝加载大于最大版本号的类文件。
  常量池(Constant Pool)
  类文件在常量池中保存与类或接口关联的常量。常量池中能看到的部分常量是字符串字面值(literal strings),final变量的值(final variable values),类名,接口名,变量名和变量类型,方法名和方法签名(method names and signatures)。方法签名由方法返回值类型(return type)和一组参数类型(argument types)组成。
  常量池被组织成一个元素长度可变的数组。每个常量占据数组中的一个元素。在整个类文件中,常量通过指示它们在数组中位置的整型索引来引用。第一个常量的索引值是1,第二个是2,以此类推。常量池数组的元素个数写在常量池的前面,所以在加载类文件时,JVM知道它需要加载多少常量。
  常量池中每个元素以指明自己类型的单字节标签(tag)开始。一旦JVM看到这个标签,就能知道接下来会遇到什么类型的常量。例如,如果看到一个表示字符串的标签,JVM会认为接下来2个字节就是字符串的长度,然后就是“长度”个字节组成的字符串。
  在本文剩下的部分,我有时会用constant_pool[n]表示常量池数组的第n个元素。从常量池组织的像个数组来说,这是有道理的;但是请记住,这些元素具有不同的大小和类型,并且第一个元素的索引是1。
  访问标识符区(Access Flags)
  常量池之后的2个字节就是访问标示符,它表明该文件定义的是类还是接口;该类或接口是公开的(public)还是抽象的(abstract);如果是类,该类是不是final的。
  当前类区(This class)
  接下来2个字节是当前类区,它是常量池数组的索引。被当前类引用的常量constant_pool[this_class],包含两部分:单字节标签(tag)和双字节名称索引(name index)。标签等于CONSTANT_Class,一个表示本元素中包含类或接口信息的值。constant_pool[name_index]是一个包含类或接口名的字符串常量。
  当前类部分稍稍揭示了常量池是怎么被使用的。当前类区本身只是一个常量池的索引。当JVM查找constant_pool[this_class]时,它找到一个用标签表明自己是一个CONSTANT_Class得元素。JVM知道CONSTANT_Class元素在标签(tag)之后,总是有一个叫名称索引(name index)的常量池双字节索引。然后它查找constant_pool[name_index],得到包含类或接口名的字符串。
.超类区(Super class)
  当前类区之后是超类区,也是2个字节的常量池索引。constant_pool[super_class]是CONSTANT_Class元素,它指向当前类所直接继承的超类名。
  接口区(Interfaces)
  接口区开头的2个字节,表示文件所定义的类(或接口)实现的接口数目。紧接着是一个数组,它包含了类所实现的每一个接口在常量池中的索引。
  每个接口都是常量池中的CONSTANT_Class元素,它指向接口名。
  字段区(Fields)
  字段部分,以表示该类或接口包含的字段数的2个字节开始。字段是一个实例变量,或者是类或接口的类变量。接下来是一个以可变长结构为元素的数组,一个结构一个字段。每个结构都包含一个字段的相关信息,如字段名,字段类型,如果是final变量,还包括字段值。部分信息在结构当中,另一部分在常量池中由结构所指向的位置。
  这部分仅有的字段,都是由定义在该类文件中的类或接口声明的变量;继承自超类或接口的字段不在此列。
  方法区(Methods)
  方法部分,以表示类或接口中方法数目的2字节开始。这个数目,只包含当前类显式定义的方法,不包括继承自超类的方法。数目之后是方法本身。
  表示每个方法的结构包含方法相关的几条信息,包括方法描述符(method descriptor,包括返回值类型和参数列表),方法本地变量需要的栈字(stack words)数,方法操作数栈(operand stack)需要的最大栈字数,方法捕获的异常表,字节码序列和行号表。
  属性区(Attributes)
  排在最后的是属性区,它提供定义在类文件中的特定类或接口的一般信息。属性区以2字节的属性数目开始,然后是属性本身。比如一个表示源码属性的属性:它表示当前类被编译而来的源文件名。JVM会悄悄地忽略任何它们识别不了的属性。

最新内容请见作者的GitHub页:http://qaseven.github.io/

相关文章
|
3月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
109 9
|
3天前
|
存储 算法 Java
解锁“分享文件”高效密码:探秘 Java 二叉搜索树算法
在信息爆炸的时代,文件分享至关重要。二叉搜索树(BST)以其高效的查找性能,为文件分享优化提供了新路径。本文聚焦Java环境下BST的应用,介绍其基础结构、实现示例及进阶优化。BST通过有序节点快速定位文件,结合自平衡树、多线程和权限管理,大幅提升文件分享效率与安全性。代码示例展示了文件插入与查找的基本操作,适用于大规模并发场景,确保分享过程流畅高效。掌握BST算法,助力文件分享创新发展。
|
2月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
170 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
3月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
192 58
|
2月前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
110 34
|
2月前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
20天前
|
前端开发 Java 开发工具
Git使用教程-将idea本地Java等文件配置到gitte上【保姆级教程】
本内容详细介绍了使用Git进行版本控制的全过程,涵盖从本地仓库创建到远程仓库配置,以及最终推送代码至远程仓库的步骤。
28 0
|
3月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
93 8
|
3月前
|
JSON Java 程序员
Java|如何用一个统一结构接收成员名称不固定的数据
本文介绍了一种 Java 中如何用一个统一结构接收成员名称不固定的数据的方法。
48 3
|
3月前
|
消息中间件 存储 Java
RocketMQ文件刷盘机制深度解析与Java模拟实现
【11月更文挑战第22天】在现代分布式系统中,消息队列(Message Queue, MQ)作为一种重要的中间件,扮演着连接不同服务、实现异步通信和消息解耦的关键角色。Apache RocketMQ作为一款高性能的分布式消息中间件,广泛应用于实时数据流处理、日志流处理等场景。为了保证消息的可靠性,RocketMQ引入了一种称为“刷盘”的机制,将消息从内存写入到磁盘中,确保消息持久化。本文将从底层原理、业务场景、概念、功能点等方面深入解析RocketMQ的文件刷盘机制,并使用Java模拟实现类似的功能。
69 3