元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

 

@Retention

Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

它的取值如下:

RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。

RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。

RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

如果@Retention不存在,则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME,所以,务必要加上@Retention(RetentionPolicy.RUNTIME)这个元注解:

@Retention(RetentionPolicy.RUNTIME)public @interface Report {

    int type() default 0;

    String level() default "info";

    String value() default "";

}

@Documented

顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

 

@Target

Target 是目标的意思,@Target 指定了注解运用的地方。

你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。

例如,定义注解@Report可用在方法上,我们必须添加一个@Target(ElementType.METHOD):

@Target(ElementType.METHOD)public @interface Report {

    int type() default 0;

    String level() default "info";

    String value() default "";

}

定义注解@Report可用在方法或字段上,可以把@Target注解参数变为数组{ ElementType.METHOD, ElementType.FIELD }:

@Target({

    ElementType.METHOD,

    ElementType.FIELD

})public @interface Report {

    ...

}

实际上@Target定义的value是ElementType[]数组,只有一个元素时,可以省略数组的写法。

 

@Inherited

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。(父类中有注解,如果子类没有注解应用,则子类会继承父类的注解)

@Repeatable(Reports.class)@Target(ElementType.TYPE)public @interface Report {

    int type() default 0;

    String level() default "info";

    String value() default "";

}

@Target(ElementType.TYPE)public @interface Reports {

    Report[] value();

}

经过@Repeatable修饰后,在某个类型声明处,就可以添加多个@Report注解:

@Report(type=1, level="debug")@Report(type=2, level="warning")public class Hello {

}

@Repeatable

Repeatable 自然是可重复的意思。通常是注解的值可以同时取多个

@Repeatable(Reports.class)@Target(ElementType.TYPE)public @interface Report {

    int type() default 0;

    String level() default "info";

    String value() default "";

}

@Target(ElementType.TYPE)public @interface Reports {

    Report[] value();

}

经过@Repeatable修饰后,在某个类型声明处,就可以添加多个@Report注解:

@Report(type=1, level="debug")@Report(type=2, level="warning")public class Hello {

}

 

Java预置的注解

@Deprecated

这个元素是用来标记过时的元素,想必大家在日常开发中经常碰到。编译器在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的方法、过时的类、过时的成员变量。

@Override

这个大家应该很熟悉了,提示子类要复写父类中被 @Override 修饰的方法

 

@SuppressWarnings

阻止警告的意思。之前说过调用被 @Deprecated 注解的方法后,编译器会警告提醒,而有时候开发者会忽略这种警告,他们可以在调用的地方通过 @SuppressWarnings 达到目的。

@SafeVarargs

参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。它是在 Java 1.7 的版本中加入的。

@FunctionalInterface

函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式编程很火,所以 Java 8 也及时添加了这个特性。函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口。

 

注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}

然后通过 getAnnotation() 方法来获取 Annotation 对象。

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

或者是 getAnnotations() 方法。

public Annotation[] getAnnotations() {}