2.11 在ClassFile、method_info、field_info中同時存在的Attribute
2.11.1 Synthetic Attribute
Synthetic Attribute用于指示當前類、接口、方法或字段由編譯器生成,而不在源代碼中存在(不包含類初始函數和實例初始函數)。相同的功能還有一種方式就是在類、接口、方法或字段的訪問權限中設置ACC_SYNTHETIC標記。
Synthetic Attribute由JDK1.1中引入,以支持內嵌類和接口(nested classes and interfaces)。但是以我現在所知,這些功能都是可以通過ACC_SYNTHETIC標記來表達的,為什么還需要存在Synthetic Attribute呢?在什么樣的情況下會生成Synthetic Attribute項呢?我還沒有找到,需要繼續研究。
Synthetic Attribute |
type | descriptor | remark |
u2 | attribute_name_index | constant_pool中的索引,CONSTANT_Utf8_info類型。指定Attribute名稱(“Synthetic”)。 |
u4 | attribute_length | 該Attribute內容的字節長度(0)。 |
2.11.2 Signature Attribute
Signature Attribute |
type | descriptor | remark |
u2 | attribute_name_index | constant_pool中的索引,CONSTANT_Utf8_info類型。指定Attribute名稱(“Signature”)。 |
u4 | attribute_length | 該Attribute內容的字節長度(2)。 |
u2 | signature_index | constant_pool中的索引,CONSTANT_Utf8_info類型。記錄當前類型的簽名(類簽名、字段簽名、方法簽名)。 |
JVM規范中沒有指定什么情況下需要生成Signature Attribute。但是從Signature的目的是用于泛型類型,可以推測Signature Attribute存在于當前Signature Attribute所在類型是泛型(泛型類、泛型方法、泛型字段)的時候。它和field_info、method_info、this_class一起對應于局部變量中的LocalVariableTable Attribute和LocalVariableTypeTable Attribute,他們同時都有descriptor版本和signature版本。
2.11.3 Deprecated Attribute
Deprecated Attribute指示當前類、方法、字段已經過時了,一些工具,如編譯器可以根據該Attribute提示用戶他們使用的類、方法、字段已經過時了,最好使用最新版本的類、方法、字段。
Deprecated Attribute |
type | descriptor | remark |
u2 | attribute_name_index | constant_pool中的索引,CONSTANT_Utf8_info類型。指定Attribute名稱(“Deprecated”)。 |
u4 | attribute_length | 該Attribute內容的字節長度(0)。 |
2.11.4 RuntimeVisibleAnnotations Attribute
RuntimeVisibleAnnotations Attribute記錄了當前類、方法、字段在源代碼中定義的、在運行時可見的Annotation。Java程序可以通過反射函數獲取這些Annotation。一個attributes集合中只能包含一項RuntimeVisibleAnnotations Attribute,記錄所有運行時可見的Annotation。
RuntimeVisibleAnnotations Attribute |
type | descriptor | remark |
u2 | attribute_name_index | constant_pool中的索引,CONSTANT_Utf8_info類型。指定Attribute名稱(“RuntimeVisibleAnnotations”)。 |
u4 | attribute_length | 該Attribute內容的字節長度。 |
u2 | num_annotations | annotations集合長度。 |
annotation | annotations[num_annotations] | 記錄所有運行時可見的annotation的集合。annotation類型詳見附錄E。 |
2.11.5 RuntimeInvisibleParameterAnotations Attribute
RuntimeInvisibleAnnotations Attribute記錄了當前類、方法、字段在源代碼中定義的、在運行時不可見的Annotation。默認情況下,這些Annotation是不可被Java提供的反射函數獲取的,需要通過和實現相關的機制來獲取這些Annotation。一個attributes集合中只能包含一項RuntimeInvisibleAnnotations Attribute,記錄所有運行時不可見的Annotation。
RuntimeInvisibleAnnotations Attribute |
type | descriptor | remark |
u2 | attribute_name_index | constant_pool中的索引,CONSTANT_Utf8_info類型。指定Attribute名稱(“RuntimeInvisibleAnnotations”)。 |
u4 | attribute_length | 該Attribute內容的字節長度。 |
u2 | num_annotations | annotations集合長度。 |
annotation | annotations[num_annotations] | 記錄所有運行時不可見的annotation的集合。annotation類型詳見附錄E。 |
總體格式
magic(0xCAFEBABE) |
version(major.minor) |
constant pool CONSTANT_Utf8_info(1) | CONSTANT_Integer_info(3) | CONSTANT_Float_info(4) | CONSTANT_Long_info(5) | CONSTANT_Double_info(6) | CONSTANT_Class_info(7) | CONSTANT_String_info(8) | CONSTANT_Fieldref_info(9) | CONSTANT_Methodref_info(10) | CONSTANT_InterfaceMethodref_info(11) | CONSTANT_NameAndType_info(12) | |
access_flags | this_class | super_class | interfaces |
fields access_flags | name | descriptor | attributes ConstantValue Attribute | Synthetic Attribute | Signature Attribute | Deprecated Attribute | RuntimeVisibleAnnotations Attribute | RuntimeInvisibleAnnotations Attribute | | |
methods access_flags | name | descriptor | attributes Code Attribute StackMapTable Attribute | LineNumberTable Attribute | LocalVariableTable Attribute | LocalVariableTypeTable Attribute | | Exceptions Attribute | RuntimeVisibleParameterAnnotations Attribute | RuntimeInvisibleParameterAnnotations Attribute | AnnotationDefault Attribute | Synthetic Attribute | Signature Attribute | Deprecated Attribute | RuntimeVisibleAnnotations Attribute | RuntimeInvisibleAnnotations Attribute | | |
attributes InnerClasses Attribute | EnclosingMethod Attribute | SourceFile Attribute | SourceDebugExtension Attribute | Synthetic Attribute | Signature Attribute | Deprecated Attribute | RuntimeVisibleAnnotations Attribute | RuntimeInvisibleAnnotations Attribute | |
附件A :Java字節碼中的類和接口名
在Java字節碼中類和接口名主要表現以下幾點:
1. 類和接口名都是以全限定名的方式存放(包名加類或接口名)。
2. 在源代碼中的點分隔符(”.”)在字節碼中以斜杠(”/”)代替。如:“java.lang.Object”-> “java/lang/Object”
3. 數組類型名做了特殊處理。如:“int[][]”-> “[[I”、“Thread[]”->“[Ljava/lang/Thread”。詳見附錄B:Java字節碼中的數組類型名
附件B : Java字節碼中的數組類型名
在Java中,數組被認為是類,因而它也有對應的類名表示,而Java字節碼為數組名指定了特定的格式:
1. 所有數組名都以“[”開頭,n維數組有n個“[”。
2. 對引用類型的數組,在“[”后加“L”后加引用類型的全限定名。
3. 對基本類型,在“[”后加基本類型的對應字符。
基本類型對應字符表 |
基本類型 | 對應字符 |
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
short | S |
boolean | Z |
附件C : 描述符(Descriptor)
描述符(Descriptor)定義了字段或方法的類型(A descriptor is a string representing the type of a field or method.這段描述感覺不怎么精確)。它存放在constant pool中的CONSTANT_Utf8_info類型項中。
1. 字段描述符(Field Descriptor)
字段描述符是定義了字段、局部變量、參數等類型的字符串。即附錄A中的類或接口名。
語法定義:
FieldDescrptor :
FieldType
BaseType : B、C、D、F、I、J、S、Z(參考附錄B中的基本類型對應字符表)
ObjectType : LfullClassName;
ArrayType : [+BaseType | [+ObjectType
FieldType : BaseType | ObjectType | ArrayType
如:[[D -> double[][]、[Ljava/lang/Thread; -> Thread[]、I->int、Ljava/lang/Object; -> Object
2. 方法描述符(Method Descriptor)
方法描述符是定義了方法參數、方法返回等信息的字符串。
語法定義:
MethodDescriptor:
(ParameterDescriptor*)ReturnDescriptor
ParameterDescriptor : FieldType
ReturnDescriptor : FieldType | VoidDescriptor
VoidDescriptor : V
如:void method(int i, Object obj)-> (ILjava/lang/Object;)V
Object getValue()-> ( )Ljava/lang/Object;
Object mymethod(int i, double d, Object o) -> (IDLjava/lang/Object;)Ljava/lang/Object;
附件D : 簽名(Signature)
簽名(Signature)定義了類、字段或方法的泛型類型信息(A signature is a string representing the generic type of a field or method, or generic type information for a class declaration. 這段描述感覺不怎么精確)。它也存放在constant pool中的CONSTANT_Utf8_info類型項中。
它存在于Signature Attribute中,只有包含泛型的類、字段、方法才會產生Signature Attribute。
簽名信息并不是給JVM用的,而是用于編譯、調試、反射。
1. 類簽名
語法定義:
ClassSignature:
FormalTypeParametersopt SuperclassSignature SuperinterfaceSignature*
FormalTypeParameters:
<FormalTypeParameter+>
FormalTypeParameter:
Identifier ClassBound InterfaceBound*
ClassBound:
: FieldTypeSignatureopt
InterfaceBound:
: FieldTypeSignature
SuperclassSignature:
ClassTypeSignature
SuperinterfaceSignature:
ClassTypeSignature
FieldTypeSignature:
ClassTypeSignature
ArrayTypeSignature
TypeVariableSignature
ClassTypeSignature:
L PackageSpecifier* SimpleClassTypeSignature
ClassTypeSignatureSuffix* ;
PackageSpecifier:
Identifier / PackageSpecifier*
SimpleClassTypeSignature:
Identifier TypeArgumentsopt
ClassTypeSignatureSuffix:
. SimpleClassTypeSignature
TypeVariableSignature:
T Identifier ;
TypeArguments:
<TypeArgument+>
TypeArgument:
WildcardIndicatoropt FieldTypeSignature
*
WildcardIndicator:
+
-
ArrayTypeSignature:
[TypeSignature
TypeSignature:
FieldTypeSignature
BaseType
以上定義沒有看懂??例子如:
對class MyClass<T> { } 定義的類,產生如下的簽名:
<T:Ljava/lang/Object;>Ljava/lang/Object;
而對以下類定義:
class MyClass<T1, T2> extends ClassFileParser implements IndexParser {
}
則產生如下簽名:
<T1:Ljava/lang/Object;T2:Ljava/lang/Object;>Lorg/levin/classfilereader/ClassFileParser;Lorg/levin/classfilereader/IndexParser;
2. 字段簽名
語法定義如上,沒能看懂。從Tomcat代碼中的Digester.class文件中可以解析得到如下的例子:
Ljava/util/HashMap<Ljava/lang/String;Ljava/util/Stack<Ljava/lang/String;>;>;(對應的descriptor:“Ljava/util/HashMap;”)
Ljava/util/Stack<Ljava/lang/Object;>;(對應的descriptor:“Ljava/util/Stack;”)
3. 方法簽名
語法定義:
MethodTypeSignature:
FormalTypeParametersopt (TypeSignature*) ReturnType
ThrowsSignature*
ReturnType:
TypeSignature
VoidDescriptor
ThrowsSignature:
^ClassTypeSignature
^TypeVariableSignature
也沒能看懂。同樣從Tomcat代碼中的Digester.class文件中可以解析得到如下例子:
(Ljava/lang/String;Ljava/lang/Class<*>;Ljava/lang/String;)V(對應descriptor:“(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;)V”)
(Ljava/lang/String;Ljava/lang/Class<*>;Ljava/lang/String;Z)V(對應descriptor:“(Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Z)V”)
()Ljava/util/Map<Ljava/lang/String;Ljava/net/URL;>;(對應descriptor:“()Ljava/util/Map;”)
附錄E:annotation結構和element_value結構
1. annotation結構
每一項annotation結構記錄一項用戶定義的annotation的值。如:
@Test(id = 4, description = "description", useCase = @UseCase())
@UseCase()
void testExecute(int a) {
}
編譯器會為該方法生成兩項annotation。每項annotation指定了annotation的類型和鍵值對。
annotation結構 |
type | descriptor | remark |
u2 | type_index | constant_pool中的索引。CONSTANT_Utf8_info類型。以字段描述符(field descriptor)方式記錄當前結構表示的annotation類型。 |
u2 | num_element_value_pairs | 記錄當前annotation中的鍵值對數。 |
element_value_pair | 記錄每項annotation中的鍵值對表。 | u2 | element_name_index | constant_pool中的索引。CONSTANT_Utf8_info類型。記錄當前annotation中當前鍵值對的鍵名。如上例的“id”、“description”等。 | element_value | value | 當前annotation中當前鍵值對的值。詳見element_value結構一節。 | element_value_pairs[num_element_value_pairs] | |
2. element_value結構
element_value結構記錄了所有annotation類型的鍵值對中的值。它是一個聯合類型,可以表示多種類型的值。
element_value結構 |
type | descriptor | remark |
u1 | tag | tag記錄了當前annotation鍵值對中值的類型,’B’、’C’、’D’、’F’、’I’、’J’、’S’、’Z’表示基本類型(見附錄B中的基本類型對應表);其他的合法值有: ’s’ -> String ‘e’ -> enum constant ‘c’ -> class ‘@’ -> annotation type ‘[‘ -> array |
value 聯合體類型(union) | union類型,記錄當前annotaion鍵值對中的值。 | u2 | constant_value_index | constant_pool中的索引,索引項必須是常量類型。當tag中的值為’B’ ‘C’ ‘D’ ‘F’ ‘I’ ‘J’ ‘S’ ‘Z’ ‘s’時該項有效。 | enum_const_value | 當tag值為’e’時,該項有效。記錄枚舉類型值。 | u2 | type_name_index | constant_pool中的索引,CONSTANT_Utf8_info類型。記錄當前枚舉類型二進制名(binary name,好像就是類型名,以descriptor的形式表示)。 | u2 | const_name_index | constant_pool中的索引,CONSTANT_Utf8_info類型。記錄當前枚舉類型的值(枚舉類型內部成員字符串)。 | enum_const_value | u2 | class_info_index | constant_pool中的索引,CONSTANT_Utf8_info類型。以descriptor記錄當前值所表達的Class類型。當tag值為’c’時,該項有效。 | annotation | annotation_value | 當tag值為’@’時,該項有效。記錄當前annotation鍵值對中的值為內嵌的annotation。 | array_value | 當tag值為’[‘時,該項有效。記錄當前annotation鍵值對中的值為數組類型。 | u2 | num_values | 數組的長度。 | element_value | values[num_values] | 每一項記錄數組中的值。 | array_value | value | |
注:從這個結構中,我們也可以得出annotation中可以設置的值類型:
1. 基本類型值(byte、char、double、float、int、long、short、boolean)
2. 字符串(String)
3. 枚舉(enum)
4. 類實例(Class)
5. 嵌套注解類型(annotation)
6. 以上所有以上類型的一維數組。
于2010-12-19日