注解的定义方式为
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
String name() default "ryy";
}
@Target和@Retention为源注解,就是给我们自己定义的注解说明一个生效时间以及生效位置的注解,jdk自带。
这里不重点介绍,主要介绍下我们定义的注解到底是个什么呢?它又能做些什么呢?
看@interface 这种类型 就比 interface 多一个 @,其实注解本质是一个继承了Annotation的特殊接口,也就是说它也是一个interface。
这个interface在程序运行时都做了些什么?
在获取注解对象时,实际上是获取的它的代理对象。
interface Human{
void say();
}
@TestAnnotation
class Student implements Human{
@Override
public void say() {
System.out.println("student 说:");
}
}
这里定义了一个Student类,它上边加了一个之前定义好的注解TestAnnotation。
public class Test {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Student student = new Student();
TestAnnotation annotation = student.getClass().getAnnotation(TestAnnotation.class);
System.out.println(annotation.name());
}
}
启动程序,new一个Student对象,并将它的TestAnnotation对象拿出来。
跟进getAnnotation方法,可以看到,实际上是从一个Map中把我们定义的注解取出来(AnnotationData是Class类中的一个静态内部类)。
// annotation data that might get invalidated when JVM TI RedefineClasses() is called
private static class AnnotationData {
final Map<Class<? extends Annotation>, Annotation> annotations;
.........
}
这个Map中存的是一些什么对象?
使用了
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
所以,在程序执行中生成的代理类,都会被导出。看一下生成的代理类。
public final class $Proxy1 extends Proxy implements TestAnnotation {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final String name() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Class annotationType() throws {
try {
return (Class)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
}
可以看到,生成了一个类实现了我们自己定义的注解TestAnnotation,并且实现了它的抽象方法name()
name()方法中调用了父类的InvocationHandler的invoke方法,注解使用的InvocationHandler是
class AnnotationInvocationHandler implements InvocationHandler, Serializable
看到这个类中的invoke()方法中,如果是自己定义的方法,比如这个name(),就会从它自己的
private final Map<String, Object> memberValues 中去通过方法名去get(),比如"name"。
而这个 memberValues就是创建代理对象时通过解析RuntimeVisibleAnnotations时得到并传给AnnotationInvocationHandler的。