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;
而對以下類定義:
classMyClass<T1, T2> extendsClassFileParser implementsIndexParser {
}
則產生如下簽名:
<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()
voidtestExecute(inta) {
}
編譯器會為該方法生成兩項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. 以上所有以上類型的一維數組。
作者“上善若水”