butterknife源码分析系列:
谈一谈Java的注解
http://blog.csdn.net/u012933743/article/details/54909590
如何处理注解—反射与注解处理器
http://blog.csdn.net/u012933743/article/details/54972050
代码分析
http://blog.csdn.net/u012933743/article/details/64437988
有时,我们希望在程序运行或者编译时能获取注解的值,并做一些处理。如何想运行时处理注解,需要通过反射(Reflect),此时要将@Retention设置为RUNTIME;如果是编译时,需要用到注解处理器(AbstractProcessor),并将@Retention需要设置为CLASS。
反射
反射机制允许在运行时发现和使用类的信息。Class类与java.lang.reflect一起对反射的概念进行了支持,允许在运行时利用反射达到:
- 判断任意一个对象所属的类;
- 构造任意一个类的对象;
- 判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
- 调用任意一个对象的方法
其实我觉得反射是个很bug般的存在,连private的都能进行操作。不过,反射会对性能有影响,因为JVM无法对反射部分的代码进行优化。在http://docs.oracle.com/javase/tutorial/reflect/
中有说到:
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
这里举个简单的栗子对反射的运用进行介绍。
注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReflectParam {
String value() default "nobody";
}
反射是在运行中获取类的信息,因此需要将注解的声明周期设置为RUNTIME,@Retention(RetentionPolicy.RUNTIME)。
Main函数
public class ReflectMain {
@ReflectParam("jerry")
public String userName;
public static void main(String[] args) {
ReflectMain main = new ReflectMain();
ReflectParam annotation = null;
try {
Class clazz = main.getClass();
Field field = clazz.getField("userName");
annotation = field.getAnnotation(ReflectParam.class);
System.out.print(annotation.value());
} catch (NoSuchFieldException e) {
System.out.print("no such field");
}
}
}
ReflectParam是修饰域变量的注解(@Target(ElementType.FIELD)),因此需要先通过反射获取Field。Field、Method、Constructor内都有getAnnotation来获取注解的方法。获取到ReflectParam注解后,直接通过注解内定义的方法来获取注解的值,这里我们定义的方法是value()。
输出结果如下, 因此通过反射可以获取到注解的值并做一些处理。
jerry
Process finished with exit code 0
在写这篇博客时,突然想到比较二的问题,这里也跟大家分享下。我们的ReflectParam注解内的value方法是没有用权限关键词修饰的,那位什么在Main函数内可以直接用annotation.value()来调用呢?不加权限关键词的默认难道不是default(包权限)吗?
其实这是一个陷阱,@interface默认继承自java.lang.annotation.Ann