和常量池类似,各种属性表达的信息也各不相同
不同之处在于,常量是由Java虚拟机规范严格定义的,共有14种。
但属性是可以扩展的,不同的虚拟机实现可以定义自己的属性类型,因此无法用统一的结构来定义。由于这个原因,Java虚拟机规范没有使用tag,而是使用属性名来区别不同的属性。属性数据放在属性名之后的u1表中,这样Java虚拟机实现就可以跳过自己无法识别的属性。
属性的结构定义如下:
attribute_info {
u2 attribute_name_index;//属性名 常量池索引,指向常量池中的CONSTANT_Utf8_info
u4 attribute_length;//长度
u1 info[attribute_length];
}
Java虚拟机规范预定义了23种属性:
这个ClassFileTest.class为例
package jvmgo.book.ch03;
public class ClassFileTest {
//常量池里面的类型都是 CONSTANT_Integer_info
public static final boolean FLAG = true;
public static final byte BYTE = 123;
public static final char X = 'X';
public static final short SHORT = 12345;
public static final int INT = 123456789;
public static final long LONG = 12345678901L;
public static final float PI = 3.14f;
public static final double E = 2.71828;
public static void main(String[] args) throws RuntimeException {
System.out.println("Hello, World!");
}
}
Deprecated和Synthetic属性(本例没有)
Deprecated和Synthetic是最简单的两种属性,仅起标记作用,不包含任何数据。这两种属性都是JDK1.1引入的,可以出现在ClassFile、field_info和method_info结构中,它们的结构定义如下:
Deprecated_attribute {
u2 attribute_name_index;
u4 attribute_length;//0
}
Synthetic_attribute {
u2 attribute_name_index;
u4 attribute_length;//0
}
由于不包含任何数据,所以attribute_length的值必须是0。
Deprecated属性用于指出类、接口、字段或方法已经不建议使用,编译器等工具可以根据Deprecated属性输出警告信息。
Synthetic属性用来标记源文件中不存在、由编译器生成的类成员,引入Synthetic属性主要是为了支持嵌套类和嵌套接口。
SourceFile属性(ClassFile属性 一级目录最下面)
可选定长属性,只会出现在ClassFile结构中,用于指出源文件名。
SourceFile_attribute {
u2 attribute_name_index;
u4 attribute_length;//必须2
u2 sourcefile_index;//常量池索引,指向CONSTANT_Utf8_info常量
}
ConstantValue属性(static field常量的值)
ConstantValue是定长属性,只会出现在field_info结构中,
用于表示常量表达式的值(详见Java语言规范的15.28节)。
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;//2
u2 constantvalue_index;//常量池索引
}
attribute_length的值必须是2。constantvalue_index是常量池索引
具体指向哪种常量因字段类型而异。
Code属性(method属性)
变长属性,只存在于method_info结构中,存放字节码等方法相关信息
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];
}
Exceptions属性(method属性,方法有写着抛异常就有)
变长属性,记录方法抛出的异常
Exceptions_attribute {
u2 attribute_name_index;
u4 attribute_length;//长度
u2 number_of_exceptions;//个数
u2 exception_index_table[number_of_exceptions];
}
LineNumberTable LocalVariableTable(Code属性的属性)
method属性的Code属性的属性
LineNumberTable 方法的行号
LocalVariableTable 方法的局部变量
和前面介绍的SourceFile属性都属于调试信息,都不是运行时必需的。在使用javac编译器编译Java程序时,默认会在class文件中生成这些信息。可以使用javac提供的-g:none选项来关闭这些信息的生成
LineNumberTable_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 line_number_table_length;
{
u2 start_pc;
u2 line_number;
} line_number_table[line_number_table_length];
}