天天看點

Java位元組碼(.class檔案)格式詳解(三)

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

constant_pool中的索引,constant_utf8_info類型。指定attribute名稱(“signature”)。

該attribute内容的位元組長度(2)。

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

constant_pool中的索引,constant_utf8_info類型。指定attribute名稱(“deprecated”)。

2.11.4     runtimevisibleannotations attribute

runtimevisibleannotations attribute記錄了目前類、方法、字段在源代碼中定義的、在運作時可見的annotation。java程式可以通過反射函數擷取這些annotation。一個attributes集合中隻能包含一項runtimevisibleannotations attribute,記錄所有運作時可見的annotation。

runtimevisibleannotations attribute

constant_pool中的索引,constant_utf8_info類型。指定attribute名稱(“runtimevisibleannotations”)。

該attribute内容的位元組長度。

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

constant_pool中的索引,constant_utf8_info類型。指定attribute名稱(“runtimeinvisibleannotations”)。

記錄所有運作時不可見的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

name

attributes

constantvalue attribute

methods

code attribute

stackmaptable attribute

linenumbertable attribute

localvariabletable attribute

localvariabletypetable attribute

exceptions attribute

runtimevisibleparameterannotations attribute

runtimeinvisibleparameterannotations attribute

annotationdefault attribute

innerclasses attribute

enclosingmethod attribute

sourcefile attribute

sourcedebugextension 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:

fieldtypesignature:

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_index

constant_pool中的索引。constant_utf8_info類型。以字段描述符(field descriptor)方式記錄目前結構表示的annotation類型。

num_element_value_pairs

記錄目前annotation中的鍵值對數。

element_value_pair

記錄每項annotation中的鍵值對表。

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結構

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鍵值對中的值。

constant_value_index

constant_pool中的索引,索引項必須是常量類型。當tag中的值為’b’ ‘c’ ‘d’ ‘f’ ‘i’ ‘j’ ‘s’ ‘z’ ‘s’時該項有效。

enum_const_value

當tag值為’e’時,該項有效。記錄枚舉類型值。

type_name_index

constant_pool中的索引,constant_utf8_info類型。記錄目前枚舉類型二進制名(binary name,好像就是類型名,以descriptor的形式表示)。

const_name_index

constant_pool中的索引,constant_utf8_info類型。記錄目前枚舉類型的值(枚舉類型内部成員字元串)。

class_info_index

constant_pool中的索引,constant_utf8_info類型。以descriptor記錄目前值所表達的class類型。當tag值為’c’時,該項有效。

annotation_value

當tag值為’@’時,該項有效。記錄目前annotation鍵值對中的值為内嵌的annotation。

array_value

當tag值為’[‘時,該項有效。記錄目前annotation鍵值對中的值為數組類型。

num_values

數組的長度。

values[num_values]

每一項記錄數組中的值。

注:從這個結構中,我們也可以得出annotation中可以設定的值類型:

1.       基本類型值(byte、char、double、float、int、long、short、boolean)

2.       字元串(string)

3.       枚舉(enum)

4.       類執行個體(class)

5.       嵌套注解類型(annotation)

6.       以上所有以上類型的一維數組。