Java类文件的基本结构-阿里云开发者社区

开发者社区> 晚来风急> 正文

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/

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
MapReduce将小文件合并成大文件,并设置每个切片的大小的案例
测试代码: package cn.toto.bigdata.combinefile; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; imp
2758 0
Java对文件的读、写随机访问,RandomAccessFile类的使用分析
  在网上看了一些关于java中的RandomAccessFile类的介绍,又经过查看Java API和自己编的测试程序,总算是对RandomAccessFile的使用有了一定的了解。自己做了以下比较详细的总结吧。
1032 0
Flume监听文件夹中的文件变化,并把文件下沉到hdfs
1、采集目录到HDFS 采集需求:某服务器的某特定目录下,会不断产生新的文件,每当有新文件出现,就需要把文件采集到HDFS中去 根据需求,首先定义以下3大要素 采集源,即source——监控文件目录 : spooldir 下沉目标,即sink——HDFS文件系统 : hdfs sink source和sink之间的传递通道——channel,可用file chann
3724 0
Ubuntu下解决bash 没有那个文件或目录的方法
因为之前电脑硬盘坏掉,维修换了新硬盘,今天重新安装了ubuntu,装好之后就赶紧搭建工作环境,将备份的资料拷贝进来,搭建交叉编译环境,但是发现,修改bashrc中PATH绝对路径指向交叉编译器后,在命令行下运行交叉编译器或出现说没有这个文件或者目录,但是按照绝对路径ls看又有这个文件,很是奇怪。
922 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
12037 0
MySQL---数据库从入门走向大神系列(九)-用Java向数据库读写大文本/二进制文件数据
介绍MySQL的文本和图形数据类型: Text 类型: 数据类型:描述 ------------------------------------------------------ char(size):保存固定长度的字符串(可包含字母、数字以及特殊字符)。
997 0
+关注
9380
文章
243
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载