首先看一个自定义的注解:
1、自定义注解
public @interface MyAnnotation {
int age();
}
可见定义一个注解非常简单,只需要使用@interface关键字来定义即可。
同时我们可以看到,注解的内部可以定义变量,但是在定义变量之后必须加上括号()。
使用:
public class Test {
@MyAnnotation(age = 15) //使用自定义的注解
public static void main(String[] args) {
}
}
我们必须指明注解属性age的值,如果不想指明,而想给自定义注解设置一个默认值的话,可以这样写: int age() default 15; 使用default可以给自己的注解属性设置默认值。
public @interface MyAnnotation {
int age() default 15;
}
这样使用的时候即使不指明age的值也可以正常使用:
@MyAnnotation//使用自定义的注解
public static void main(String[] args) {
}
2、Retention和RetentionPolicy
Retention 翻译过来就是保留,滞留的意思,它也是一个注解,它可以用来表示我们的自定义注解的作用周期。
RetentionPolicy是一个枚举类型,它里面定义了注解的三种作用周期:源码期,CLASS文件时,运行时
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME;
private RetentionPolicy() {
}
}
SOURCE :此注解的信息只会记录在源文件中,编译时将被编译器丢弃,即此注解信息不回保留字编译好的class文件中。我们的自定义注解通常不会用到这种类型。
@Override和@SuppressWarnings就是此类注解,注解信息只能在源文件中出现。
CLASS:编译器将把注解记录在class文件中,但不会被加载到JVM中,如果我们自定义的注解没有声明作用范围,那么将默认是CLASS注解。这种注解被称为编译时注解。
RUNTIME:此注解的信息将会保留在源文件,class文件中,并且会在运行的时候加载到JVM中,因此这种注解可以通过反射读取。这种注解被称为运行时注解。
@Deprecated 就是此类注解,注解信息在执行时出现
我们很容易可以发现,一个注解的运行周期:RUNTIME>CLASS>SOURCE
总结一下就是:
如果要做一些源码的检查操作用SOURCE
如果要做一些预处理操作,比如生成代码就用CLASS,例如ButterKnife
如果要在运行时通过反射操作,动态的获取注解信息,就只能用RUNTIME
使用一下Retention:
@Retention(value = RetentionPolicy.RUNTIME)//表明我们的注解是一个运行时注解
public @interface MyAnnotation {
int age() default 15;
}
3、元注解
如上面的代码,像Retention这种用来表示注解的特殊注解,就被称为元注解。
其它的元注解还有:
@Target:表明注解作用的目标
@Document:表明注解将被包含在javadoc中
@Inherited:表明子类可以继承父类中的此注解
@Repeatable:java se8中引入的表明注解可以重复应用在同一个目标上
@Target的使用类型:@Target(ElementType.XXXX)
public enum ElementType {
TYPE, //接口、类、枚举、注解
FIELD, //字段、枚举的常量
METHOD,//方法
PARAMETER,//方法参数
CONSTRUCTOR,//构造函数
LOCAL_VARIABLE,//局部变量
ANNOTATION_TYPE,//注解
PACKAGE,//包
TYPE_PARAMETER,//类型,1.8以后添加
TYPE_USE;//类型,1.8以后添加
private ElementType() {
}
}