一、什么是注解

我们都知道在Java代码中使用注释是为了提升代码的可读性,对于编译器来说没有意义。注解可以可以向编译器、虚拟机等解释说明一些事情。比如我们非常熟悉的@Override注解,它的作用是告诉编译器它所注解的方法是重写的父类中的方法,这样编译器就会去检查父类是否存在这个方法,以及这个方法的签名与父类是否相同。注解是一种被动的信息,必须由编译器或虚拟机来主动解析它,它才能发挥自己的作用。

二、元注解

元注解即用来描述注解的注解,比如以下代码中我们使用“@Target”元注解来说明MethodInfo这个注解只能用于对方法进行注解:


@Target(ElementType.METHOD)
public @interface MethodInfo 
{    ... 
}

从以上代码中可以看到,定义注解使用@interface关键字,这就好比我们定义类时使用class关键字,定义接口时使用interface关键字一样,注解也是一种类型。

常用的元注解:

1.Retention

这个元注解表示一个注解的生命周期。取值有以下三种:

RetentionPolicy.SOURCE: 只在源代码中保留,不会包含在编译后产生的class文件中。一般都是用来增加代码的理解性或者帮助代码检查之类的,比如我们的Override;

RetentionPolicy.CLASS: 默认的选择,能把注解保留到编译后的字节码class文件中,运行时会被移除;

RetentionPolicy.RUNTIME: ,注解不仅能保留到class字节码文件中,在运行时可以JVM访问到,我们可以在运行时通过反射解析这个注解,这也是我们最常用的。

2.Target

这个元注解说明了被修饰的注解的应用范围,也就是被修饰的注解可以用来注解哪些程序元素,它的取值是为ElementType[]类型,ElementType是一个枚举类型,它可以取以下值:

ElementType.TYPE:能修饰类、接口、注解或枚举类型

ElementType.FIELD:能修饰成员变量

ElementType.METHOD:能修饰方法

ElementType.PARAMETER:能修饰参数

ElementType.CONSTRUCTOR:能修饰构造器

ElementType.LOCAL_VARIABLE:能修饰局部变量

ElementType.ANNOTATION_TYPE:能修饰注解

ElementType.PACKAGE:能修饰包

3.Documented

当一个注解被@Documented元注解所修饰时,那么无论在哪里使用这个注解,都会被Javadoc工具文档化。

4.Inherited

表明被修饰的注解类型是自动继承的。如果你想让一个类和它的子类都包含某个注解,就可以使用@Inherited来修饰这个注解。也就是说,假设Parent类是Child类的父类,那么我们若用被@Inherited元注解所修饰的某个注解对Parent类进行了修饰,则相当于Child类也被该注解所修饰了。

自定义一个注解如下:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Documented
@Inherited
public @interface Bind {
    int value() default 1;
    boolean canBeNull() default false;
}

用@interface 表明这是一个注解,Annotation只有成员变量,没有方法。Annotation的成员变量在Annotation定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。比如上面的value和canBeNull。

三、Android 中的注解&反射(以Butterknife为例)

在使用Butterknife插件之前,我们用的是findViewById。如果使用了Butterknife 框架,我们就可以很方便的完成findViewById的工作。例:

public class ButtferknifeDemoActivity extends AppCompatActivity {
    @BindView(R.id.textView)
    TextView textView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_buttferknife);
        ButterKnife.bind(this);
        textView.setText("OK");
    }
}

现在我们不用框架,自己写一个注解实现这个功能:

public class InjectActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        displayInjectView();
    }

    private void displayInjectView() {
        Class<?> classname = this.getClass();
        Field[] fields = classname.getDeclaredFields();//获得声明的成员变量
        for (Field field : fields) {
            //判断是否有注解
            try {
                if (field.getAnnotations() != null) {
                    if (field.isAnnotationPresent(BindView.class)) {
                        //为这个控件设置属性
                        field.setAccessible(true);//允许修改反射属性
                        ViewInject inject = field.getAnnotation(BindView.class);
                        field.set(this, this.findViewById(inject.value()));
                    }
                }
            } catch (Exception e) {
                  throw new InterruptedException("not found view id!");
            }
        }
    }
}
public class ButtferknifeDemoActivity extends InjectActivity {

    @BindView(R.id.textView)
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        textView.setText("OK");        
    }
}





参考文献:

www.jianshu.com/p/d4978bbce12a