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
| |||||||||||||||||||||
access_flags | this_class | super_class | interfaces | ||||||||||||||||||
fields
| |||||||||||||||||||||
methods
| |||||||||||||||||||||
attributes
|
附件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中的鍵值對數。 | |||||||||||||||
|
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 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
注:從這個結構中,我們也可以得出annotation中可以設置的值類型:
1. 基本類型值(byte、char、double、float、int、long、short、boolean)
2. 字符串(String)
3. 枚舉(enum)
4. 類實例(Class)
5. 嵌套注解類型(annotation)
6. 以上所有以上類型的一維數組。
于2010-12-19日