本文主要是介绍认识一下java的注解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
如果我们通过method.getAnnotation(xx)方法,去获取对应的注解。我们可以发现,注解都是一个动态生成的Proxy类。
示例一个注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Ann0tation {String attr();
}
$Proxy126.通过执行getClass().getName()方法,得到对应的proxy类名为com.sun.proxy.$Proxy126.
这个类只有一个属性h。而h就是这样一个类:sun.reflect.annotation.AnnotationInvocationHandler.
这里就涉及java生成的Proxy类。通过 Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this)就可以生成一个动态的类。该类就是注解对应的类。
注解对应的各个方法,是在proxy类中生成的。类似这样:
public final String attr(){try{return (String)this.h.invoke(this, m3, null);}catch (Error|RuntimeException localError){throw localError;}catch (Throwable localThrowable){throw new UndeclaredThrowableException(localThrowable);}}
对应的注解的属性,其实是在Proxy类的唯一的属性h中的。
h的构造函数为:
private final Map<String, Object> memberValues;
AnnotationInvocationHandler(Class<? extends Annotation> paramClass, Map<String, Object> paramMap){Class[] arrayOfClass = paramClass.getInterfaces();if ((!paramClass.isAnnotation()) || (arrayOfClass.length != 1) || (arrayOfClass[0] != Annotation.class)){throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");}this.type = paramClass;this.memberValues = paramMap;}
因此,最终缓存的属性其实都是存储在memberValues的map中。我们看到attr方法最终是调用的是,(String)this.h.invoke(this, m3, null);方法。我们先看下Proxy类和h是如何关联起来的。
Proxy
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
内部方法走到
final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}return cons.newInstance(new Object[]{h});
依旧是最终调用了Proxy的构造函数
protected Proxy(InvocationHandler h) {Objects.requireNonNull(h);this.h = h;}
也就是Proxy的newProxyInstance最终是把InvocationHandler的实现类设置到Proxy类的h属性中了。
因为注解的h对应的就是sun.reflect.annotation.AnnotationInvocationHandler.。来看下该类的
String)this.h.invoke(this, m3, null);方法
主要是这么两句话:
public Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject) {String str = paramMethod.getName();
....localObject = this.memberValues.get(str);
....
return localObject;
}
示例的Ann0tation 举例来说,调用attr的时候,methodName为attr。然后memberValues本质上就是一个map,key就是attr,value就是attr对应的值。这样就通过map得到了attr方法返回的值了。并返回数据。
总结:
注解因为可以调用对应的方法。例如示例中的attr方法等。注解的class通过javap反编译后,可以看到其实注解就是一个接口。
示例对应的是:
public
interface
me.kisimple.just4fun.Ann0tation
extends
java.lang.annotation.Annotation
但是我们的代码中又可以写成Ann0tation.attr方法。因此这里具体实现必然是该接口的一个实现。对jdk来说,就是采用
Proxy类生成一个代理类。代理类的注解方法的实现实际上都会调用Proxy的唯一的属性h的invoke方法,在h的invoke方法中,
其实就是从map中获取对应的方法名的value值。该value值就是在使用注解中写的例如attr="xx",对应的map中key->value为
attr->xx。在invoke方法中返回xx即可。
参考文章:
Java之道系列:Annotation实现机制
这篇关于认识一下java的注解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!