6.1 java class文件

一个class文件中只能包含一个类或者接口。
占据多个字节空间的项按照高位在前的顺序分为几个连续的字节存放。
可变长度的ClassFile表中的项,如表6-2所示,按照它们在class文件中出现的顺序列出了主要部分。

表6-2 ClassFile表的格式

类型

名 称

数量

u4

magic

1

u2

minor_version

1

u2

major_version

1

u2

constant_pool_count

1

cp_info

constant_pool

constant_pool_count

u2

access_flags

1

u2

this_class

1

u2

super_class

1

u2

interfaces_count

1

u2

interfaces

interfaces_count

u2

fields_count

1

field_info

fields

fields_count

u2

methods_count

1

method_info

methods

methods_count

u2

attributes_count

1

attribute_info

attributes

attributes_count


class文件的下面4个字节包含了主、次版本号。随着Java技术的发展,Java class文件格式可 能会加入新特性。class文件格式一旦发生变化,版本号也会随之变化。对于Java虚拟机来说,版 本号确定了特定的class文件格式,通常只有给定主版本号和一系列次版本号后,Java虚拟机才能 够读取class文件。如果class文件的版本号超出了Java虚拟机所能处理的有效范围,Java虚拟机将 不会处理该class文件。

Java虚拟机实现的第二版中修改了对Class文件主版本号和次版本号的解释。对于第二版而言, class文件的主版本号与Java平台主发布版的版本号保持一致(例如,在Java 2平台发布版上,主 版本号从45升至46),次版本号与特定主平台发布版的各个发布版相关。因此,尽管不同的class 文件格式可以由不同的版本号表示,但版本号不一样并不代表class文件格式不同。版本号不同的 原因可能只是因为class文件由不同发布版本的Java平台产生,可能class文件的格式并没有改变。

每个常量池入口都从一个长度为一个字节的标志开始,这个标志指出了列表中该位置的常 量类型。—旦Java虚拟机获取并解析这个标志,Java虚拟机就会知道在标志后的常量类型是什么。 表6-3列出了所有常量池标志的名字和值。

表6-3中的每一个标志都有一个相对应的表,表名通过在标志名后加上后缀来产生。 例如,对应于CONSTANT_Class标志的表名为CONSTANT_CIass_info,表名为 CONSTANT_Utf8_info的表中存储着Unicode字符串的压缩形式。对应于各种不同常量池人口的 表将在本章后面详细描述。

表6-3常量池标志
人口类型 标志值 描述
C0NSTANT_Utf8 1 UTF-8编码的Unicode字符串
CONSTANT_Integer 3 int类型字面值
CONSTANT_Float 4 float类型字面值
CONSTANT_Long 5 long类型字面值
CONSTANT_Double 6 double类型字面值
CONSTANT_Class 7 对一个类或接口的符号引用
CONSTANT_String 8 String类型字面值
CONSTANT_Fieldref 9 对一个字段的符号引用
CONSTANT_Methodref 10 对一个类中声明的方法的符号引用
CONSTANT_InterfaceMethodref 11 对一个接口中声明的方法的符号引用
CONSTANT_NameAndType 12 对一个字段或方法的部分符号引用


(5) this_class

接下来的两个字节为this_class项,它是一个对常量池的索引。在this_class位置的常量池人口必须为CONSTANT_class_info表。该表由两个部分组成——标签和name_index。标签部分是 —个具有CONSTANT_Class值的常量,在name_index位置的常量池入口为一个包含了类或接口全限定名的CONSTANT_Utf8_info表。

this_class项提供了一个如何使用常量池的范例。对于它自身来说,this_class项只是一个指向常量池的索引。当Java虚拟机在this_class位置查阅常量池人口的时候,它会发现一个通过把自己的标签设为CONSTANT_Class来识别自身的项。Java虚拟机知道,在CONSTANT_Class_info 人口中,标签的后面总会有一个名为name_index的、指向常量池的索引。于是虚拟机在 name_index位置查找常量池入口,在这个位置,Java虚拟机应该能找到一个容纳了类或者接口全 限定名的CONSTANT_Utf8_info人口。对于这个过程,图6-2有一个图形描述。

 

在class文件中,紧接在interfaces后面的是对在该类或者接口中所声明的字段的描述。首先是名为fields_count的计数,它是类变量和实例变量的字段的数量总和。在这个计数后面的是不 同长度的field_info表的序列(fields_count指出了序列中有多少个fieid_info表)。只有在文件中由 类或者接口声明了的宇段才能在fields列表中列出。在fields列表中,不列出从超类或者父接口继承而来的字段。另一方面,fields列表可能会包含在对应的java源文件中没有叙述的宇段,这是 因为Java编译器可能会在编译时向类或者接口添加字段。例如,对于一个内部类的fields列表来 说,为了保持对外围类实例的引用,Java编译器会为每个外围类实例添加实例变量。源代码中并 没有叙述任何在fields列表中的字段,它们是被Java编译器在编译时添加进去的,这些字段使用 Synthetic属性标识。

每个field_info表都展示了一个字段的信息。此表包含了字段的名字、描述符和修饰符。如 果该宇段被声明为final, field_info表还会展示其常量值。这样的信息有些放在field_info表中, 有些则放在由field_info表所指向的常量池中。field_info表将在本章后面进一步阐述。

method_info表中包含了与方法相关的—些信息,包括方法名和描述符(方法的返回值类型和参数类型)。如果方法既不是抽象的,又不是本地的,那么method_info表就包含方法局部变量所需的栈空间长度、为方法所捕获的异常表、字节码序列以及可选的行数和局部变量表。如果 方法能够抛出任何已验证的异常,那么method_info表就会包括一个关于这些已验证异常的列表。

(10) attributes_count 和 attributes

class文件中最后的部分是属性(attribute),它给出了在该文件中类或者接口所定义的属性 的基本信息。属性部分由attributes_count开始,attributes_count是指出现在后续attributes列表中 的attribute_info表的数量总和。每个attribute_info的第一项是指向常量池中 CONSTANT_Utf8_info表的索引,该表给出了属性的名称。

属性有许多种。Java虚拟机规范定义了几种属性,但任何人都可以创建他们自己的属性种类 (通过特定的规则),并且把它们置于class文件中。Java虚拟机实现必须忽略任何不能识别的属 性。创建新属性种类的规则将在本章后面阐述。

属性出现在class文件中的多处,而不仅仅在顶层ClassFile表的attributes项中出现。出现在 ClassFile表中的属性主要给出了与文件中所定义的类和接口相关的信息;出现在field_info表中 的属性主要给出了与字段相关的信息;出现在method_info表中的属性主要给出了与方法相关的 信息。

Java虚拟机实现定义了两种展性-SourceCode和InnerClasses,它们出现在ClassFile表中属性列表中。这两种属性将在本章后面进一步阐述。

原文地址:https://www.cnblogs.com/mongotea/p/11979512.html