注解
注解可以标注在class、field、method
上,同时又可以分为编译期
的注解,运行期
的注解。
这篇文章会结合jvm规范3.1.5说明注解在字节码中的位置。
一 、描述
注解可以标注在class
、interface
、fileds
、method
、method parameters
、type parameters
。注解甚至可以作用在包级别package
。
类似的所有的组件基本上都有一个Attribute
区域,注解是一种Attribute
被放置在部分。
使用method
的字节码来举例
1.1 methods 方法表
方法表在class文件的位置
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
// 这里
u2 methods_count;
method_info methods[methods_count];
// 结束
u2 attributes_count;
attribute_info attributes[attributes_count];
}
metod_info的的数据结构
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
// 这里
u2 attributes_count;
attribute_info attributes[attributes_count];
// 结束
}
Attribute的数据结构
属性是变长的,种类有很多。分为jvm规范中预制的,也有各厂家自定义的。但是有一个统一的格式。
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
2.2 annotations的数据结构
除了方法表之外,很多地方都有一个属性表。注解作为一个属性被放在这个位置。
注解属性结构细分有7种
type | descriptor |
---|---|
RuntimeVisibleAnnotations | 运行时可见 |
RuntimeVisibleAnnotations | 运行时不可见 |
RuntimeVisibleParameterAnnotations | 标注在参数上,运行时可见的参数型注解 |
RuntimeInvisibleParameterAnnotations | 标注在参数上,运行时不可见的参数型注解 |
RuntimeVisibleTypeAnnotations | 标注在例行上比如泛型,运行时可见的类型注解 |
RuntimeInvisibleTypeAnnotations | 标注在例行上比如泛型,运行时不可见的类型注解 |
AnnotationDefault | 注解的默认值 |
2.2.1 RuntimeVisibleAnnotations
顾名思议,就是运行期(runtime) 可见的。延伸一点,运行期可以通过函数等方式获取到的。
注解表结构
RuntimeVisibleAnnotations_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_annotations;
annotation annotations[num_annotations];
}
2.2.1.1 annotation的结构
继上一步,理解注解的结构和注解代码定义是分不开的
annotation 代码定义
这个是一个完整的定义
@Retention(RetentionPolicy.RUNTIME)
//@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Info {
// value
int age();
String name();
String descriptor() default "simple annotation";
}
一个注解可以继承注解(@Retention、@Target)
也需要定义字节的成员(int age();)
使用时如下,这是一个打印了Info注解的方法
public class TestInfo {
@Info(age = 0, name = "baby")
public void born() {
System.out.println("human born");
}
public static void main(String[] args) throws Exception {
TestInfo ti = new TestInfo()<