携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第六天,点击查看活动详情
注解(Annotation)
前言回顾
我们在注解一种已经了解了注解分为两种注解,标准注解(内置注解)和元注解,标准注解(内置注解)我们在上一篇已经了解,本篇我们将来了解元注解
- 元注解
除了标准注解就是元注解,它用来注解其他注解,从而创建新的注解。元注解有以下几种- @Target
注解所修饰的对象范围 - @Retention
用来申明注解的保留策略 - @Documented
表示这个注解应该被JavaDoc这个工具记录 - @Inherited
表示注解可以被继承 - @Repeatable JDk8新增的元注解,允许一个注解在同一个声明类型(类、属性或者方法)上多次使用
- @Target
@Target
用于描述注解的范围,即注解能在哪里使用。他说明了注解所修饰的对象范围, packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)等。这样定义注解类时使用@Target我们能够清楚地指导注解的使用范围,我们用ElementType类型的数组来定义范围,其中有以下几种取值,对应的不同对象范围
- ElementType.TYPE
能修饰类、接口或者枚举类型 - ElementType.FIELD
能修饰成员变量(包括枚举常量) - ElementType.METHOD
能修饰方法 - ElementType.PARAMETER
能修饰参数 - ElementType.CONSTRUCTOR
能修饰构造方法 - ElementType.LOCAL_VARIABLE
能修饰局部变量 - ElementType.ANNOTATION_TYPE
能修饰注解 - ElementType.PACKAGE
能修饰包 - ElementType.TYPE_PARAMETER
类型参数声明 - ElementType. TYPE_USE
使用类型
@Retention
用于描述注解保留策略,即注解的生命周期,保留的时间。
这个保留策略有三种类型,用RetentionPolicy来表示范围
- RetentionPolicy.SOURCE
源码级注解。注解信息只会保留在.java源码中,源码在编译后,注解信息会被丢弃,不会保留在.class中 - RetentionPolicy.CLASS 编译时注解。注解信息回保留在.java源码以及.class中。当运行Java程序时,JVM会丢弃该注解的信息,不会保留在JVM中
- RetentionPolicy.RUNTIME
运行时注解。当运行Java程序时,JVM也会保留该注解信息,可以通过反射获取该注解信息。
学习了@Target和@Retention那么接下来我们就以@Verride为例,看看如何使用@Target和@Retention
@Target(ElementType.METHOD)//表示该注解用于修饰方法
@Retention(RetentionPolicy.SOURCE)//表示只在源代码中保留
public @interface Override{
}
解析:
@interface是定义接口的关键字,有点类似interface,请不要搞错哦。
@Documented
@Documented 是一个标记注解,没有成员变量。用 @Documented 注解修饰的注解类会被 JavaDoc 工具提取成文档。默认情况下,JavaDoc 是不包括注解的,但如果声明注解时指定了 @Documented,就会被 JavaDoc 之类的工具处理,所以注解类型信息就会被包括在生成的帮助文档中。
接下来我们来看一下实例:
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface TestDocumented{
public String value() default "@Documented test";
}
//接下来我们来试用一下
@TestDocumented
public class DocumentedTest{
}
接下来我们用这个注解来生成一下文档,步骤如下
到这里我们就生成了HTML格式的文档,那我们来看看
@Inherited
@Inherited作用是,使用此注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。这里一定要记住,使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。
简单点:使用该注解的注解父类的子类可以继承父类的注解。
我们来看一下例子:
//定义一个注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritedTest {
String value();
}
@InheritedTest("拥有Inherited")
public class Person {
public void method(){
}
public void method2(){
}
}
//继承一个有@Inherited注解的类
public class Student extends Person {
}
public class TestInherited {
public static void main(String[] args) {
//我们用反射来拿到对象
Class<Student> studentClass = Student.class;
//检查此类中是否存InheritedTest注释类型的注释
if (studentClass.isAnnotationPresent(InheritedTest.class)){
//输出注解的值
System.out.println(studentClass.getAnnotation(InheritedTest.class).value());
}
}
}
输出结果:
拥有Inherited
我们发现注解被继承了
那我们来看看不使用@Inherited注解的情况:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface IsNotInherited {
String value();
}
@IsNotInherited("未拥有Inherited")
public class Person {
public void method(){
}
public void method2(){
}
}
public class Student extends Person {
}
public class TestInherited {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
if (studentClass.isAnnotationPresent(IsNotInherited.class)){
System.out.println(studentClass.getAnnotation(IsNotInherited.class).value());
}
}
}
输出:
(没有输出)
@Repeatable
@Repeatable是java8为了解决同一个注解不能重复在同一类、方法、属性上使用的问题。
我们来看一下列子:
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
@Retention(RetentionPolicy.RUNTIME)
public @interface Schedules {
Schedule[] value();
}
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Wed", hour=24)
public class RepetableAnnotation{
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour=23)
public void doPeriodicCleanup(){}
public static void main(String[] args) throws NoSuchMethodException {
Method doPeriodicCleanup = RepetableAnnotation.class.getMethod("doPeriodicCleanup");
Schedules schedules = doPeriodicCleanup.getAnnotation(Schedules.class);
System.out.println("获取标记方法上的重复注解:");
for (Schedule schedule: schedules.value()){
System.out.println(schedule);
}
System.out.println("获取标记类上的重复注解:");
if (RepetableAnnotation.class.isAnnotationPresent(Schedules.class)){
schedules = RepetableAnnotation.class.getAnnotation(Schedules.class);
for (Schedule schedule: schedules.value()){
System.out.println(schedule);
}
}
}
}
这一篇就结束了,下一篇我们开自定义注解