一、什么是注解(Annotation)?
简单的说就是元数据(Metadata),即一种描述数据的数据。所以说注解就是源代码的元数据。更具体的就是一种应用于类、方法、参数、变量、构造器及包声明中的特殊修饰符。它是一种由JSR-175标准选择用来描述元数据的一种工具。JDK5中引入了Metadata很容易的就能够调用注解。
二、为什么引入注解?
在Annotation出现前,XML被广泛的应用于描述元数据。在开发过程中一些应用开发人员和架构师发现XML的维护越来越糟糕。他们希望使用一些和代码紧耦合的东西,而不是像XML那样和代码是松耦合的(在某些情况下甚至是完全分离的)代码描述,于是就出现了注解。目前,许多框架将XML和Annotation两种方式结合使用,平衡两者之间的利弊。
三、注解的语法与定义形式
- 以@interface关键字定义
- 注解包含成员,成员以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。
- 成员赋值是通过@Annotation(name=value)的形式。
- 注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。
Java提供了四种元注解,专门负责新注解的创建工作,即注解其他注解。
-
@Target
定义了Annotation所修饰的对象范围,Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。取值():ElementType.CONSTRUCTOR
:用于描述构造器ElementType.FIELD
:用于描述域ElementType.LOCAL_VARIABLE
:用于描述局部变量ElementType.METHOD
:用于描述方法ElementType.PACKAGE
:用于描述包ElementType.PARAMETER
:用于描述参数ElementType.TYPE
:用于描述类、接口(包括注解类型) 或enum声明ElementType. ANNOTATION_TYPE
:注解上使用的元注解
-
@Retention
定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。取值:-
RetentionPoicy.SOURCE
:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;用于做一些检查性的操作,比如 @Override 和 @SuppressWarnings -
RetentionPoicy.CLASS
:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;用于在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife) -
RetentionPoicy.RUNTIME
:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;用于在运行时去动态获取注解信息。
-
-
@Documented
标记注解,用于描述其它类型的注解应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化,不用赋值。 -
@Inherited
标记注解,允许子类继承父类的注解。
上面的理论可能不太直观,下面以与注解Target
举例说明一下:
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = { ElementType.ANNOTATION_TYPE } )
public @interface Target {
ElementType[] value();
}
1:元注解@Retention
,成员value的值为RetentionPolicy.RUNTIME
。
2:元注解@Target
,成员value是个数组,用{}形式赋值,值为ElementType.ANNOTATION_TYPE
3:成员名称为value
,类型为ElementType[]
!注意:如果成员名称是value,在赋值过程中可以简写。如果成员类型为数组,但是只赋值一个元素,则也可以简写。如上面的简写形式为:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
框架中常见注解
- JDK内置的其他注解
@Override、@Deprecated、@SuppressWarnings、@SafeVarargs、@FunctionalInterface、@Resources等。
- Android SDK内置的注解
- 资源引用限制类:用于限制参数必须为对应的资源类型
@AnimRes @AnyRes @ArrayRes @AttrRes @BoolRes @ColorRes
等 - 线程执行限制类:用于限制方法或者类必须在指定的线程执行
@AnyThread @BinderThread @MainThread @UiThread @WorkerThread
- 参数为空性限制类:用于限制参数是否可以为空
@NonNull @Nullable
- 类型范围限制类:用于限制标注值的值范围
@FloatRang @IntRange
- 类型定义类:用于限制定义的注解的取值集合
@IntDef @StringDef
- 资源引用限制类:用于限制参数必须为对应的资源类型
Android SDK 内置的注解都在包com.android.support:support-annotations
里,具体的使用介绍见官方文档:传送门
Java注解的思维导图
最后引用网上大神的一张思维导图如下: