您的位置:首页 > 编程语言 > Java开发

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

2013-01-10 16:45 369 查看
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.
以上所有以上类型的一维数组。

转自:http://www.blogjava.net/DLevin/archive/2011/09/05/358035.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: