JAVA虚拟机不仅仅可以执行JAVA语言编译的字节码文件,也可以执行任何语言编译的符合规范的字节码文件。那我们来看看Class文件是什么样子的。
首先,任何一个Class文件都只对应着唯一的类和接口。它是一组以8位字节为基础单位的二进制流。根据规范,Class文件格式采用一种类似C语言结构体的伪结构来储存数据,数据类型分为无序号数和表。
无序号数属于基本的数据类型,用来描述数字,索引引用,数量值或者按照UTF-8编码构成的字符串值。
表是由多个无符号数或者其他表作为数据项构成的符合数据类型,用于表述有层次关系的复合数据类型。
实际上Class文件本身就是一张表。当需要描述多个数据,就要用到容量计数器作为集合。
每个Class文件的头4个字节为魔数,它的作用是确定这个Class文件是否能被虚拟机接受。紧接着它们的是Class版号。其中第5,6节是次版本号,第7,8节是主版本号。
紧接着版号之后的常量池入口,也就是Class文件的资源仓库,。常量池主要存放字面量和符号引用。字面量就是广义上的常量,而符号引用则包括以下内容:类和结构的全限定名,字段的名称和描述符,方法的名称和描述符。每一项常量都是一张表,,表开始的第一位代表这张表常量的类型。而每种常量都有着自己的结构,
常量池后面,紧接着两个字节代表访问标志,用于一些类或者接口层次的访问。
类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的集合,Class文件中由这三项数据来确定这个类的继承关系。
字段表是用于表述接口或者类中声明的常量,包括类级变量以及实例级变量。可以包括的信息有:字段的作用域,是实例变量还是类变量,可变性,并发可见性,可否被序列化,字段数据类型,字段名称。
方法表结构和字段表一样,包括了访问标志,名称索引,描述符索引,属性表集合。
Class文件,字段表,方法表都可以携带自己的属性表集合,用来描述专某些情况的专有信息。分为:
Code属性,储存字节码指令。
Exceptions属性,列举可能抛出的受查异常。
LineNumberTable属性,描述JAVA源码行号与字节码行号的关系。
LocalVariableTable属性,描述栈帧中局部变量表中的变量与源码中定义的变量之间的关系。
SourceFile属性,记录生成Class文件源码的名称。
ConstantValue属性,通知虚拟机自动为静态变量赋值。
InnerClasses属性,记录内部类和宿主类之间的关系。
Deprecated属性,表示某个类,字段或者方法已经被程序作者推荐不再使用。
Synthetic属性,表示此字段或者方法不是源码产生的,而是编译器自行添加的。
StackMapTable属性,是类型检查验证器。
Signature属性,定长属性。
BootstrapMethods属性,变长属性。