Java虚拟机规范 Java SE 8版 - class文件格式(二)
-
- 4.5 字段
- 4.6 方法
- 4.7 属性
-
- 4.7.1 自定义和命名新的属性
- 4.7.2 ConstantValue 属性
- 4.7.3 Code 属性
- 4.7.4 StackMapTable 属性
- 4.7.5 Exceptions 属性
- 4.7.6 InnerClasses 属性
- 4.7.7 EnclosingMethod 属性
- 4.7.8 Synthetic 属性
- 4.7.9 Signature 属性
- 4.7.10 SourceFile 属性
- 4.7.11 SourceDebugExtension 属性
- 4.7.12 LineNumberTable 属性
- 4.7.13 LocalVariableTable 属性
- 4.7.14 LocalVariableTypeTable 属性
- 4.7.15 Deprecated 属性
- 4.7.16 RuntimeVisibleAnnotations 属性
- 4.7.17 RuntimelnvisibleAnnotations 属性
- 4.7.18 RuntimeVisibleParameterAnnotations 属性
- 4.7.19 RuntimelnvisibleParameterAnnotations 属性
- 4.7.20 RuntimeVisibleTypeAnnotations 属性
- 4.7.21 RuntimelnvisibleTypeAnnotations 属性
- 4.7.22 AnnotationDefault 属性
- 4.7.23 BootstrapMethods 属性
- 4.7.24 Methodparameters 属性
4.5 字段
每个字段(field)都由field_info结构所定义。
在同一个class文件中,不会有两个字段同时具有相同的字段名和描述符(见4.3.2小节)。 field_info结构格式如下:
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
field_info结构各项的说明如下:
- access_flags
access_flags 项的值是个由标志构成的掩码,用来表示字段的访问权限和基本属性。access_flags 中的每个标志,开启后的含义如表4-4所示。
表4-4 表示字段访问权限和属性的各个标志
标志名 | 值 | 说明 |
---|---|---|
ACC_PUBLIC | 0x0001 | 声明为public,可以从包外访问 |
ACC_PRIVATE | 0x0002 | 声明为private,只能在定义该字段的类中访问 |
ACC_PROTECTED | 0x0004 | 声明为protected,子类可以访问 |
ACC_STATIC | 0x0008 | 声明为static |
ACC_FINAL | 0x0010 | 声明为final,对象构造好之后,就不能直接设置该字段了 (JLS § 17.5) |
ACC_VOLATILE | 0x0040 | 声明为volatile,被标识的字段无法缓存 |
ACC_TRANSIENT | 0x0080 | 声明为transient,被标识的字段不会为持久化对象管理器所写入或读取 |
ACC_SYNTHETIC | 0x1000 | 被表示的字段由编译器产生,而没有写源代码中 |
ACC_ENUM | 0x4000 | 该字段声明为某个枚举类型(enum)的成员 |
class文件中的字段可以设置多个如表4-4所示的标志。不过有些标志是互斥的,一个字段最多只能设置 ACC_PRIVATE,ACC_PROTECTED 和 ACC_PUBLIC ( JLS § 8.3.1 ) 3 个标志中的一个,也不能同时设置标志 ACC_FINAL 和 ACC_VOLATILE (JLS §8.3.1.4)。接口中的所有字段都具有 ACC_PUBLIC、ACC_STATIC 和 ACC_FINAL 标志,也可以设置 ACC_SYNTHETIC 标志,但是不能含有表4-4中的其他标志(JLS §9.3)。
如果字段带有 ACC_SYNTHETIC 标志,则说明这个字段不是由源码产生的,而是由编译器自动产生的。
如果字段带有 ACC_ENUM 标志,这说明这个字段是一个枚举类型的成员。
表4-4 中没有出现的 access_flags 标志,是为了将来扩充而预留的,在生成的 class文件中应设置成0,Java虚拟机实现也应该忽略它们。
- name_index
name_index 项的值必须是对常量池表的一个有效索引。常量池表在该索引处的成员必须是CONSTANT_Utf8_info (见4.4.7小节)结构,此结构表示一个有效的非限定名,这个名称对应于本字段(见4.2.2小节)。 - descriptor_index
descriptor_index 项的值必须是对常量池表的一个有效索引。常量池表在该索引处的成员必须是CONSTANT_Utf8_info (见4.4.7小节)结构,此结构表示一个有效的字段的描述符(见4.3.2小节)。 - attributes_count
attributes_count 的项的值表示当前字段的附加属性(见4.7节)的数量。 - attributes[ ]
属性表(attributes表)中的每个成员,其值必须是 attribute_info 结构(见4.7节)。 一个字段可以关联任意多个属性。
由本规范所定义,且可以出现在 field_info 结构 attributes 表里的各属性,列在表4-8中。
field_info 结构 attributes 表里的各项预定义属性,其规则在4.7节中给出。 field_info 结构 attributes 表里的各项非预定义(non-predehned)属性,其规则在4.7.1小节中给出。
4.6 方法
所有方法(method),包括实例初始化方法以及类或接口初始化方法(见2.9节)在内, 都由 method_info 结构来定义。
在一个class文件中,不会有两个方法同时具有相同的方法名和描述符(见4.3.3小节)。
method_info 结构格式如下:
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
method_info 结构各项的说明如下:
- access_flags
access_flags 项的值是由用于定义当前方法的访问权限和基本属性的各标志所构成的掩码。各标志开启之后的含义,如表4-5所示。
表4-5 表示方法访问权限及属性的各标志
标志名 | 值 | 说明 |
---|---|---|
ACC_PUBLIC | 0x0001 | 声明为public,可以从包外访问 |
ACC_PRIVATE | 0x0002 | 声明为private,只能从定义该方法的类中访问 |
ACC_PROTECTED | 0x0004 | 声明为protected,子类可以访问 |
ACC_STATIC | 0x0008 | 声明为static |
ACC_FINAL | 0x0010 | 声明为final,不能被覆盖(见5.4.5小节) |
ACC_SYNCHRONIZED | 0x0020 | 声明为synchronized,对该方法的调用,将包装在同步锁(monitor)里 |
ACC_BRIDGE | 0x0040 | 声明为bridge方法,由编译器产生 |
ACC_VARARGS | 0x0080 | 表示方法带有变长参数 |
ACC_NATIVE | 0x0100 | 声明为native,该方法不是用Java语言实现的 |
ACC_ABSTRACT | 0x0400 | 声明为abstract,该方法没有实现代码 |
ACC_STRICT | 0x0800 | 声明为strictfp,使用FP-strict浮点模式 |
ACC_SYNTHETIC | 0x1000 | 该方法是由编译器合成的,而不是由源代码编译出来的 |
class文件中的方法可以设置多个如表4-5所示的标志,但是有些标志是互斥的:一 个方法只能设置ACC_PR工VATE、ACC_PROTECTED 和 ACC_PUBLIC 这3个标志中的一个(JLS § 8.4.3 )。
接口方法可以设置表4-5里面除 ACC_PROTECTED、ACC_FINAL、ACC_SYNCHRONIZED 及ACC_NATIVE 之外的标志(JLS §9.4)。如果class文件的版本号小于52.0,那么接口中的每个方法必须设置 ACC_PUBLIC 及 ACC_ABSTRACT 标志;如果class文件的版本号大于或等于52.0,那么接口中的每个方法,必须设置 ACC_PUBLIC 或 ACC_PRIVATE 标志中的一个。
如果一个方法被设置 ACC_ABSTRACT 标志,则这个方法不能被设置 ACC_ FINAL、ACC_NATIVE、ACC_PRIVATE、ACC_STATIC、ACC_STRICT 或 ACC_ SYNCHRONIZED 标志(JLS §8.4.3.1、JLS §8.4.3.3、JLS §8.4.3.4)。
实例初始化方法(见2.9节)只能被 ACC_PRIVATE、ACC_PROTECTED 和 ACC_ PUBLIC 中的一个标识;还可以设置 ACC_STRICT、ACC_VARARGS 和 ACC_ SYNTHETIC 标志,但是不能再设置表4-5中的其他标志了。
类或接口初始化方法(见2.9节)由Java虚拟机隐式自动调用,它们的 access_flags 项的值除了 ACC_STRICT 标志外,其他标志都将被忽略。
ACC_BRIDGE 标志用于说明这个方法是由Java编译器生成的桥接方法㊀。
㊀ 桥接方法是JDK 1.5引入泛型后,为了使Java的范型方法生成的字节码和1.5版本前的字节码相兼容,由
编译器自动生成的方法。一译者注
ACC_VARARGS 标志用于说明方法在源码层的参数列表是否变长。如果是变长的,则在编译时,必须把方法的ACC_VARARGS 标志置1,其余方法的 ACC_VARARGS 标志必须置0。
如果方法被 ACC_SYNTHETIC 标志标识,这说明这个方法是由编译器生成的并且不会在源码中出现,少量的例外情况将在4.7.8小节中提到。
表4-5 中没有出现的 access_flags 标志位,是给将来预留的。它们在生成的class文件中应设置成0,Java虚拟机实现应该忽略它们。
-
name_index
name_index 项的值必须是对常量池表的一个有效索引。常量池表在该索引处的成员必须是CONSTANT_Utf8_info (见4.4.7小节)结构,它要么表示一个特殊方法的名字(<init>或见2.9节),要么表示一个方法的有效非限定名 (见4.2.2小节)。 -
descriptor_index
descriptor_index 项的值必须是对常量池表的一个有效索引。常量池表在该索引处的成员必须是CONSTANT_Utf8_info(见447小节)结构,此结构表示一个有效的方法的描述符(见4.3.3小节)。本规范在未来的某个版本中可能会要求:当 access_flags 项的 ACC_VARARGS 标 记被设置时,方法描述符中的最后一个参数描述符必须是数组类型。
-
attributes_count
attributes_count 的项的值表示当前方法的附加属性(见4.7节)的数量。 -
attributes [ ]
属性表的每个成员的值必须是attribute(见4.7节)结构。
一个方法可以有任意个关联属性。
由本规范所定义,且可以出现在 method_info 结构 attributes 表(属性表)里的各属性,列在表4-6中。
method_info 结构 attributes 表里的各项预定义属性,其规则在4.7节中给出。 method_info 结构 attributes 表里的各项非预定义(non-predefined)属性,其规则在4.7.1小节中给出。
4.7 属性
属性(attribute)在class文件格式中的ClassFile(见4.1节)结构、field_ info(见4.5节)结构、method_info(见4.6节)结构 和 Code_attribute(见4.7.3小节)结构都有使用。
所有属性的通用格式如下:
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
对于任意属性,attribute_name_index 必须是对当前class文件的常量池的有效16位无符号索引。常量池在该索引处的成员必须是CONSTANT_Utf8_info(见4.4.7小节)结构,用以表示当前属性的名字。attribute_length 项的值给出了跟随其后的信息字节的长度,这个长度不包括 attribute_name_index 和 attribute_length 项的6个字节。
本规范预定义了23个属性。它们以3种排列形式印在3张表格中,为了查阅方便,现将这3张表格解说如下:
- 表4-6 按照属性在本章的小节序号来排列。每个属性旁边还列出了该属性首次定义哪个版本的class文件格式之中,以及该格式所对应的Java SE平台版本。(对于版本比较旧的class文件格式来说,列出的是该格式的JDK发行版本号,而不是Java SE平台的版本号。)
- 表4-7 按照首次定义该属性的class文件格式版本号来排序。
- 表4-8 按照每个属性在class文件中应该出现的位置来排序。
本规范提到的这些属性,也就是在class文件结构 attributes 表(属性表)里出现的这些预定义属性(predefined attribute),其名称是保留的,属性表中的自定义属性不能再使用这些名称。
凡是出现在 attributes 表中的预定义属性,本节都会专门用一个小节来指出其用法。 若是没有另行说明,那就意味着该属性可以在 attributes 表中出现任意次。
这些预定义属性,可以按照用途分为下面三组:
- 对Java虚拟机正确解读class文件起关键作用的5个属性:
- ConstantValue
- Code
- StackMapTable
- Exceptions
- BootstrapMethods
对于版本是V的class文件来说,如果Java虚拟机能够识别这个版本为V的class文件,而V又大于或等于首次定义某属性的class文件格式版本,同时这个属性还出现在它应该出现的位置上,那么,虚拟机必须能够识别并正确读取此属性。
- 对Java SE平台的类库正确解读class文件起关键作用的12个属性:
- InnerClasses
- EnclosingMethod
- Synthetic
- Signature
- RuntimeVisibleAnnotations
- RuntimelnvisibleAnnotations
- RuntimeVisibleParameterAnnotations
- RuntimelnvisibleParameterAnnotations
- RuntimeVisibleTypeAnnotations
- RuntimelnvisibleTypeAnnotations
- AnnotationDefault
- MethodParameters
对于版本是V的class文件来说,如果Java SE平台的类库实现(an implementation of the class libraries)能够识别这个版本为V的class文件,而V又大于或等于首次定义某属性的class文件格式版本,同时这个属性还出现在它应该出现的位置上,那么,类库实现必须能够识别并正确读取此属性。
- 对Java虚拟机或Java SE平台类库能够正确解读class文件虽然不起关键作用,但却可以作为实用工具来使用的6个属性:
- SourceFile
- SourceDebugExtension
- LineNumberTable
- LocalVariableTable
- LocalVariableTypeTable
- Deprecated
Java虚拟机实现或Java SE平台类库实现可以有选择地使用这些属性。实现可以使用这些属性所包含的信息,但若不使用这些属性,则必须默默地忽略(silently ignore)它们。
表4-6 class文件中预定义的属性(按讲解该属性的章节排序)
属性名 | 章节 | class文件 | Java SE |
---|---|---|---|
Constantvalue | 4.7.2小节 | 45.3 | 1.0.2 |
Code | 4.7.3小节 | 45.3 | 1.0.2 |
StackMapTable | 4.7.4小节 | 50.0 | 6 |
Exceptions | 4.7.5小节 | 45.3 | 1.0.2 |
InnerClasses | 4.7.6小节 | 45.3 | 1.1 |
EnclosingMethod | 4.7.7小节 | 49.0 | 5.0 |
Synthetic | 4.7.8小节 | 45.3 | 1.1 |
Signature | 4.7.9小节 | 49.0 | 5.0 |
SourceFile | 4.7.10小节 | 45.3 | 1.0.2 |
SourceDebugExtension | 4.7.11小节 | 49.0 | 5.0 |
LineNumberTable | 4.7.12小节 | 45.3 | 1.0.2 |
LocalVariableTable | 4.7.13小节 | 45.3 | 1.0.2 |
LocalVariableTypeTable | 4.7.14小节 | 49.0 | 5.0 |
Deprecated | 4.7.15小节 | 45.3 | 1.1 |
RuntimeVisibleAnnotations | 4.7.16小节 | 49.0 | 5.0 |
RuntimeInvisibleAnnotations | 4.7.17小节 | 49.0 | 5.0 |
RuntimeVisibleParameterAnnotations | 4.7.18小节 | 49.0 | 5.0 |
RuntimeInvisibleParameterAnnotations | 4.7.19小节 | 49.0 | 5.0 |
RuntimeVisibleTypeAnnotations | 4.7.20小节 | 52.0 | 8 |
RuntimelnvisibleTypeAnnotations | 4.7.21小节 | 52.0 | 8 |
AnnotationDefault | 4.7.22小节 | 49.0 | 5.0 |
BootstrapMethods | 4.7.23小节 | 51.0 | 7 |
MethodParameters | 4.7.24小节 | 52.0 | 8 |
表4-7 class文件中预定义的属性(按class文件版本排序)
属性名 | class文件 | Java SE | 章节 |
---|---|---|---|
Constantvalue | 45.3 | 1.0.2 | 4.7.2小节 |
Code | 45.3 | 1.0.2 | 4.7.3小节 |
Exceptions | 45.3 | 1.0.2 | 4.7.5小节 |
SourceFile | 45.3 | 1.0.2 | 4.7.10小节 |
LineNumberTable | 45.3 | 1.0.2 | 4.7.12小节 |
LocalVariableTable | 45.3 | 1.0.2 | 4.7.13小节 |
InnerClasses | 45.3 | 1.1 | 4.7.6小节 |
Synthetic | 45.3 | 1.1 | 4.7.8小节 |
Deprecated | 45.3 | 1.1 | 4.7.15小节 |
EnclosingMethod | 49.0 | 5.0 | 4.7.7小节 |
Signature | 49.0 | 5.0 | 4.7.9小节 |
SourceDebugExtension | 49.0 | 5.0 | 4.7.11小节 |
LocalVariableTypeTable | 49.0 | 5.0 | 4.7.14小节 |
RuntimeVisibleAnnotations | 49.0 | 5.0 | 4.7.16小节 |
RuntimeinvisibleAnnotations | 49.0 | 5.0 | 4.7.17小节 |
RuntimeVisibleParameterAnnotations | 49.0 | 5.0 | 4.7.18小节 |
RuntimeInvisibleParameterAnnotations | 49.0 | 5.0 | 4.7.19小节 |
AnnotationDefault | 49.0 | 5.0 | 4.7.22小节 |
StackMapTable | 50.0 | 6 | 4.7.4小节 |
BootstrapMethods | 51.0 | 7 | 4.7.23小节 |
RuntimeVisibleTypeAnnotations | 52.0 | 8 | 4.7.20小节 |
RuntimelnvisibleTypeAnnotations | 52.0 | 8 | 4.7.21小节 |
Methodparameters | 52.0 | 8 | 4.7.24小节 |
表4-8 class文件中预定义的属性(按属性应该出现的位置排序)
属性名 | 位置 | class文件 |
---|---|---|
SourceFile | ClassFile | 45.3 |
InnerClasses | ClassFile | 45.3 |
EnclosingMethod | ClassFile | 49.0 |
SourceDebugExtension | ClassFile | 49.0 |
BootstrapMethods | ClassFile | 51.0 |
Constantvalue | field_info | 45.3 |
Code | method_info | 45.3 |
Exceptions | method_info | 45.3 |
RuntimeVisibleParameterAnnotations,RuntimeInvisibleParameterAnnotations | method_info | 49.0 |
AnnotationDefault | method_info | 49.0 |
MethodParameters | method_info | 52.0 |
Synthetic | ClassFile,field_info,method_info | 45.3 |
Deprecated | ClassFile,field_info,method_info | 45.3 |
Signature | ClassFile,field_info,method_info | 49.0 |
RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations | ClassFile,field_info,method_info | 49.0 |
LineNumberTable | Code | 45.3 |
LocalVariableTable | Code | 45.3 |
LocalVariableTypeTable | Code | 49.0 |
StackMapTable | Code | 50.0 |
RuntimeVisibleTypeAnnotations,RuntimeInvisibleTypeAnnotations | ClassFile,field_info,method_info,Code | 52.0 |
4.7.1 自定义和命名新的属性
Java虚拟机规范允许编译器在class文件的class文件结构、field_info结构、 method_info结构以及Code属性的属性表中定义和发布新的属性。Java虚拟机实现允许识别并使用这些属性表中出现的新属性。但是,所有未在class文件规范中定义的属性,不能影响class文件的语义。Java虚拟机实现必须忽略它不能识别的自定义属性。
例如,编译器可以定义新的属性用于支持与特定发行者相关(vendor-specific)的调试, 而不影响其他Java虚拟机实现。因为Java虚拟机实现必须忽略它们不能识别的属性,所以与特定发行者相关的虚拟机实现所使用的class文件也可以被别的Java虚拟机实现使用, 即使这些class文件包含的附加调试信息不能被那些虚拟机实现所用。
Java虚拟机规范明确禁止Java虚拟机实现仅仅因为class文件包含新属性而抛出异常或以其他形式拒绝使用class文件。当然,如果class文件没有包含所需的属性,那么某些工具可能无法正确操作这个class文件。
当两个不同的属性使用了相同的属性名且长度也相同时,无论虚拟机识别其中哪一个,都会引起冲突。本规范定义之外的自定义属性,必须按照《Java语言规范(Java SE8版)》 (JLS § 6.1 )中所规定的包命名方式来命名。
本规范在未来的版本中可能会再增加一些预定义的属性。
4.7.2 ConstantValue 属性
Constantvalue属性是定长属性,位于field_info (见4.5节)结构的属性表中。 Constantvalue属性表示一个常量表达式(JLS § 15.28)的值,其用法如下:
如果该字段为静态字段(即field_info结构的access_flags项设置了 ACC_STATIC 标志),则说明这个field_info结构所表示的字段,将赋值为它的Constantvalue属性所表示的值,这个过程也是该字段所在类或接口初始化阶段(见5.5节)的一部分。这个过程发生在调用类或接口的类初始化方法(见2.9节)之前。
- 如果field_info结构表示的非静态字段包含了 Constantvalue属性,那么这个属性必须被虚拟机所忽略。
在field_info结构的属性表中,最多只能有一个Constantvalue属性。
Constantvalue属性的格式如下:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
ConstantValue_attribute结构各项的说明如下:
- attribute_name_index
attribute_name_index 项的值必须是对常量池的一个有效索引。常量池表在该索引处的成员必须是CONSTANT_Utf8_info(见4.4.7小节)结构,用以表示字符串 “ConstantValue ”。 - attribute_length
ConstantValue_attribute 结构的 attribute_length 项的值固定为 2。 - constantvalue_index
constantvalue_index 项的值必须是对常量池的一个有效索引。常量池表在该索引处的成员给出了该属性所表示的常量值。这个常量池项的类型必须适用于当前字段,适用关系见表4-9。
表4-9 ConstantValue属性的类型
字段类型 | 项类型 |
---|---|
long | CONSTANT_Long |
float | CONSTANT_Float |
double | CONSTANT_Double |
int、short、char、byte、boolean | CONSTANT_Integer |
String | CONSTANT_String |
4.7.3 Code 属性
Code属性是变长属性,位于method_info(见4.6节)结构的属性表中。Code属性中包含某个方法、实例初始化方法、类或接口初始化方法(见2.9节)的Java虚拟机指令及相关辅助信息。
如果方法声明为 native 或者 abstract 方法,那么 method_info 结构的属性绝不能有Code属性。在其他情况下,method_info 必须有且只能有一个Code属性。
Code属性的格式如下:
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{
u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table [ exception_table_length ];
u2 attributes_count;
attribute_info attributes [ attributes_count ];
}
Code_attribute 结构各项的说明如下:
- attribute_name_index
attribute_name_index 项的值必须是对常量池表的一个有效索引。常量池表在该索引处的成员必须是CONSTANT_Utf8_info(见4.4.7小节)结构,用以表示字符串 “Code”。 - attribute_length
attribute_length 项的值给出了当前属性的长度,不包括初始的6个字节。 - max_stack
max_stack 项的值给出了当前方法的操作数栈在方法执行的任何时间点的最大深度(见2.6.2小节)。 - max_locals
max_locals 项的值给出了分配在当前方法引用的局部变量表中的局部变量个数(见2.6.1小节),其中也包括调用此方法时用于传递参数的局部变量。
long和double类型的局部变量的最大索引是 max_locals - 2,其他类型的局部变量的最大索引是 max_locals - 1。 - code_length
code_length 项的值给出了当前方法 code [ ] 数组的字节数。
code_length 的值必须大于0,即 code [ ] 数组不能为空。 - code [ ]
code [ ] 数组给出了实现当前方法的Java虚拟机代码的实际字节内容。
当一台可按字节寻址的(byte-addressable)机器把code数组读入内存时,如果 code [ ] 数组的第一个字节是按4字节边界对齐,那么tableswitch和lookupswitch指令中所有的32位偏移量也都是按4字节长度对齐的(关于 code[ ] 数组边界对齐方式对字节码的影响,请参考相关指令的描述)。
本规范对关于 code[ ] 数组内容的详细约束有很多,将在后面的4.9节中列出。 - exception_table_length
exception_table_length 项的值给出了 exception_table 表的成员个数。 - exception_table [ ]
exception_table [ ] 数组的每个成员表示 code [ ] 数组中的一个异常处理器。exception_table [ ] 的异常处理器顺序是有意义的(不能随意更改,详细内容见2.10节)。
exception_table [ ] 的每个成员包含如下4项:- start_pc 和 end_pc
start_pc 和 end_pc 两项的值表明了异常处理器在 code [ ] 中的有效范围。 start_pc 的值必须是对当前code [ ] 中某一指令操作码的有效索引,end_ pc 的值要么是对当前 code [ ] 中某一指令操作码的有效索引,要么等于code_ length的值,即当前 code [ ] 的长度。start_pc 的值必须比 end_pc 小。
当程序计数器在范围 [ start_pc,end_pc )内时,异常处理器就将生效。即设 x 为异常处理器的有效范围内的值,x 应满足:start_pc ≤ x < \leq x < ≤x< end_pc。
end_pc 本身并不处在异常处理器的有效范围内,这一点属于Java虚拟机历史上的一个设计缺陷:如果Java虚拟机中某方法的Code属性长度刚好是65 535个字节, 并且以一个单字节长度的指令结束,那么这个指令将不能被异常处理器所处理。不过编译器可以通过限制任何方法、实例初始化方法或静态初始化方法的 code[ ] 项最大长度为65 534来弥补这个Bug。 - handler_pc
handler_pc 项的值表示一个异常处理器的起点。handler_pc 的值必须同时是对当前 code[ ] 和其中某一指令操作码的有效索引。 - catch_type
如果 catch_type 项的值不为0,那么它必须是对常量池表的一个有效索引。常量池表在该索引处的成员必须是CONSTANT_Class_info(见4.4.1小节)
- start_pc 和 end_pc