1
JDK元注解
@Retention
@Retention只能修饰注解定义,用于指定被修饰的注解可以保留多长时间,@Retention包含了一个RetentionPolicy类的value变量,所以使用此注解时必须为该value变量赋值。源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
public enum RetentionPolicy {
// 注解之保留在源代码中,编译器直接丢弃这种注解
SOURCE,
// 编译器将把注解记录仪在class文件中,当运行java程序时,
//JVM不可获取注解信息,---默认值
CLASS,
//编译器将把注解记录在class文件中,当运行java程序时,
//JVM也可以获取注解信息,程序代码里也可以通过反射获取注解信息
RUNTIME
}
两种使用方式:
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRetentionAnnotation {
}
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyRetentionAnnotation {
}
提示
如果使用注解时只需要为value成员变量指定值,则使用该注解时可以直接在该注解后的括号里指定value的值,无须使用value=值的形式。
@Target
@Target也是只能修饰注解定义,他用于指定被修饰的注解能用于修饰哪些程序单元,@Target元注解也包括一个value的变量。看源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
@Target中的value变量对应的是一个枚举ElementType;
public enum ElementType {
//指定该策略的注解可以修饰类、接口(包括注解类型)或枚举定义
TYPE,
//指定该策略的注解只能修饰成员变量的定义
FIELD,
//指定该测录的注解只能修饰方法的定义
METHOD,
//指定该策略的注解可以修饰参数
PARAMETER,
//指定该策略的注解只能修饰构造器
CONSTRUCTOR,
//指定该策略的注解只能修饰局部变量
LOCAL_VARIABLE,
//指定该策略的注解只能修饰注解
ANNOTATION_TYPE,
//指定该策略的注解只能修饰包定义
PACKAGE,
//JDK1.8版本开始
//指定该策略的注解只能修饰参数类型的定义
TYPE_PARAMETER,
//JDK1.8版本开始
//指定该策略的注解只能修饰一个类型的使用
TYPE_USE
}
定义方式和@Retention一样。
@Documented
@Ducumented用于指定被该元注解修饰的注解将被javadoc工具提取成文档,如果定义注解类时使用了@Documented修饰,则所有使用该注解修饰的程序元素的API文档中将会包含该注解说明。其源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
案例:
@Documented
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyRetentionAnnotation {
//自定义注解 加上注解Documented
}
public class MyTest {
//使用自定义注解
@MyRetentionAnnotation
public String annotation() {
return super.toString();
}
}
找到当前类路径,然后执行:
javadoc -d doc MyTest.java
打开index.html
进入MyTest
ok,文档已经生成,这个注解的作用也就体现出来了。
@Inherited
@Inherited元注解指定被他修饰的注解将具有继承性,如果某个类使用了@Xxx注解同事@Xxx注解上有@Inherited修饰,则其子类将自动被@Xxx修饰。
案例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyInherited {
//自定义注解
}
把自定义注解注解于父类上,
@MyInherited
public class BaseInherited {
}
//子类继承父类
public class InheritedDemo extends BaseInherited {
public static void main(String[] args) {
//InheritedDemo上是否有注解Inherited
System.out.println(
InheritedDemo.class.isAnnotationPresent(MyInherited.class));
}
}
运行结果:true。证明子类继承了父类的@MyInherited。
2
自定义注解
定义注解
文章前面部分已经写过好几次自定义注解了。还是继续说说,首先是注解的定义:只要在接口中的interface前面加一个@就变成注解了。表达不是很完美。请看下面:
//定义一个简单的注解
public @interface MyAnnotation {
}
注解通常放在所有修饰符之前,使用:
public class MyTest {
@MyAnnotation
public String annotation() {
return "Java后端技术栈";
}
}
@MyAnnotation
public class MyTest {
public String annotation() {
return super.toString();
}
}
根据注解是否可以包含成员变量、可以把注解分为如下两类:
1:标记注解,没有定义成员变量@override和@MyAnnotation等注解。
2:元素注解,包含成员变量的注解,因为他们可以接受更多的元素据,所以也被称之为元数据注解
提取注解
使用反射获取注解相关信息,在java.lang.Class中有几个方法跟注解有关系:
下面来一个使用案例
先自定义一个注解:
/**
* 自定义注解
* @author lawt
* @date 2019/6/28
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
String value() default "";
}
/**
* @author lawt
* @date 2019/6/28
*/
@MyAnnotation(value = "Java后端技术栈")
public class MyMyAnnotationDemo {
public static void main(String[] args) {
boolean hasMyAnnotation = MyMyAnnotationDemo.class.isAnnotationPresent(MyAnnotation.class);
if (hasMyAnnotation) {
MyAnnotation myAnnotation = MyMyAnnotationDemo.class.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.value());
}
}
}
输出
ok,自此提取注解结束,提取注解的其他方法请自行试试。我们在工作中一般无非就是使用到自定义注解和提取注解是使用最频繁之一。