Java字节码(.class文件)格式详解(三)

2.11 ClassFilemethod_infofield_info中同时存在的Attribute

2.11.1     Synthetic Attribute

Synthetic Attribute用于指示当前类、接口、方法或字段由编译器生成,而不在源代码中存在(不包含类初始函数和实例初始函数)。相同的功能还有一种方式就是在类、接口、方法或字段的访问权限中设置ACC_SYNTHETIC标记。

 

Synthetic AttributeJDK1.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_infomethod_infothis_class一起对应于局部变量中的LocalVariableTable AttributeLocalVariableTypeTable 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记录了当前类、方法、字段在源代码中定义的、在运行时可见的AnnotationJava程序可以通过反射函数获取这些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


 

附件Java字节码中的类和接口名

 

Java字节码中类和接口名主要表现以下几点:

1.       类和接口名都是以全限定名的方式存放(包名加类或接口名)。

2.       在源代码中的点分隔符”.”在字节码中以斜杠”/”代替。如:“java.lang.Object-> java/lang/Object

3.       数组类型名做了特殊处理。如:“int[][]-> [[I”、“Thread[]->[Ljava/lang/Thread”。详见附录BJava字节码中的数组类型名

 

 

附件 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

 

附件 描述符(Descriptor

 

描述符(Descriptor)定义了字段或方法的类型(descriptor is a string representing the type of a field or method.这段描述感觉不怎么精确)。它存放在constant pool中的CONSTANT_Utf8_info类型项中。

 

1.       字段描述符(Field Descriptor

字段描述符是定义了字段、局部变量、参数等类型的字符串。即附录A中的类或接口名。

语法定义:

FieldDescrptor :

FieldType

 

BaseType  BCDFIJSZ(参考附录B中的基本类型对应字符表)

ObjectType  LfullClassName;

ArrayType  [+BaseType | [+ObjectType

FieldType  BaseType | ObjectType | ArrayType

如:[[D -> double[][][Ljava/lang/Thread; -> Thread[]I->intLjava/lang/Object; -> Object

 

2.       方法描述符(Method Descriptor

方法描述符是定义了方法参数、方法返回等信息的字符串。

语法定义:

MethodDescriptor:

         ParameterDescriptor*ReturnDescriptor

 

ParameterDescriptor  FieldType

ReturnDescriptor  FieldType | VoidDescriptor

VoidDescriptor  V

如:void methodint 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;

 

附件 签名(Signature

 

签名(Signature)定义了类、字段或方法的泛型类型信息(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:

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;”)

 

附录Eannotation结构和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.       基本类型值(bytechardoublefloatintlongshortboolean

2.       字符串(String

3.       枚举(enum

4.       类实例(Class

5.       嵌套注解类型(annotation

6.       以上所有以上类型的一维数组。

上一篇:Firefox 火狐下自动刷新的插件 ReloadEvery


下一篇:阿里云云效智能化代码平台的探索与实践