Oracle官方对注解的定义为:
Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.
注解是元数据的一种形式,它提供有关程序的数据,该数据不属于程序本身。 注解对其注释的代码操作没有直接影响。
而在JDK的Annotation接口中有一行注释如此写到:
/** * The common interface extended by all annotation types. * ... */ public interface Annotation {...}这说明其他注解都扩展自 Annotation 这个接口,也就是说注解的本质就是一个接口。
以 Spring Boot 中的一个注解为例:
它实际上相当于:
public interface Component extends Annotation{...}而@interface 可以看成是一个语法糖。
1.2注解的要素依然来看 @Component 这个例子:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed public @interface Component { String value() default ""; }在注解定义上有几个注解@Target, @Retention, @Documented,被称为 元注解。
所谓元注解就是说明注解的注解
Java 中的元注解共有以下几个:
1.2.1 @Target@Target顾名思义,这个注解标识了被修饰注解的作用对象。我们看看它的源码:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value(); }可以看到,这个注解的 value 值是一个数组,这也就意味着注解的作用对象可以有多个。 其取值范围都在ElementType这个枚举之中:
public enum ElementType { /** 类、接口、枚举定义 */ TYPE, /** 字段,包括枚举值 */ FIELD, /** 方法 */ METHOD, /** 参数 */ PARAMETER, /** 构造方法 */ CONSTRUCTOR, /** 局部变量 */ LOCAL_VARIABLE, /** 元注解 */ ANNOTATION_TYPE, /** 包定义 */ PACKAGE... }不同的值代表被注解可修饰的范围,例如TYPE只能修饰类、接口和枚举定义。这其中有个很特殊的值叫做 ANNOTATION_TYPE, 是专门表示元注解的。
在回过头来看 @Component 这个例子, Target 取值为 TYPE。熟悉 Spring Boot 的同学也一定知道,@Component 确实是不能放到方法或者属性前面的。
1.2.2@Retention@Retention 注解指定了被修饰的注解的生命周期。定义如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value(); }可以看到这个注解带一个 RetentionPolicy 的枚举值:
public enum RetentionPolicy { SOURCE, CLASS, RUNTIME }SOURCE 表示注解编译时可见,编译完后就被丢弃。这种注解一般用于在编译器做一些事情;
CLASS 表示在编译完后写入 class 文件,但在类加载后被丢弃。这种注解一般用于在类加载阶段做一些事情;
RUNTIME 则表示注解会一直起作用。
1.2.3 @Documented这个注解比较简单,表示是否添加到 java doc 中。
1.2.4 @Inherited这个也比较简单,表示注解是否被继承。这个注解不是很常用。
注意:元注解只在定义注解时被使用!
1.3 注解的构成从上面的元注解可以了解到,一个注解可以关联多个 ElementType,但只能有一个 RetentionPolicy:
Java 中有三个常用的内置注解,其实相信大家都用过或者见过。不过在了解了注解的真实面貌以后,不妨重新认识一下吧!
1.4 Java内置注解 1.4.1 @Override@Override它的定义为:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }可见这个注解没有任何取值,只能修饰方法,而且RetentionPolicy 为 SOURCE,说明这是一个仅在编译阶段起作用的注解。
它的真实作用想必大家一定知道,就是在编译阶段,如果一个类的方法被 @Override 修饰,编译器会在其父类中查找是否有同签名函数,如果没有则编译报错。可见这确实是一个除了在编译阶段就没什么用的注解。
1.4.2 @Deprecated@Deprecated它的定义为:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }