在JDK中提供了几个标准的用来对注解类型进行注解的注解类(annotation of annotation),我们称之为 meta-annotation(元注解),他们分别是:
- Documented:标志将此注解包含至javadoc中
- Inherited: 注解允许继承
- Retention: 定义注解保存级别
- Target: 定义注解适用的目标
- Repeatable: 可以重复的注解 jdk 1.8新增
- Native:表示一个定义常量值的字段可以从本机代码被引用。
我们可以使用元注解来对我们自定义的注解类型进行注解
@Target注解
Target注解的作用是:描述注解的使用范围(即被修饰的注解可以用在什么地方).
Target注解用来说明那些被它所注解的注解类可修饰的对象范围:注解可以用于修饰 packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数),在定义注解类时使用了@Target 能够更加清晰的知道它能够被用来修饰哪些对象,它的取值范围定义在ElementType 枚举中.
@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();
}
@Retention注解
Reteniton注解的作用是:描述注解保留的时间范围(即:被描述的注解在它所修饰的类中可以被保留到何时).
Reteniton注解用来限定那些被它所注解的注解类在注解到其他类上以后,可被保留到何时,一共有三种策略,定义在RetentionPolicy枚举中.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
@Documented注解
Documented注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。
/**
* Indicates that annotations with a type are to be documented by javadoc
* and similar tools by default. This type should be used to annotate the
* declarations of types whose annotations affect the use of annotated
* elements by their clients. If a type declaration is annotated with
* Documented, its annotations become part of the public API
* of the annotated elements.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
这里验证@Documented的作用,我们创建一个自定义注解:
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyDocumentedt {
public String value() default "这是@Documented注解为文档添加的注释";
}
然后创建一个测试类,在方法和类上都加入自定义的注解
@MyDocumentedt
public class MyDocumentedTest {
/**
* 测试 document
* @return String the response
*/
@MyDocumentedt
public String test(){
return "sdfadsf";
}
}
打开java文件所在的目录下,打开命令行输入:
javac .\MyDocumentedt.java .\MyDocumentedTest.java
javadoc -d doc .\MyDocumentedTest.java .\MyDocumentedt.java
打开生成的doc文件夹,打开index.html,可以发现在类和方法上都保留了 MyDocumentedt 注解信息。
@Inherited注解
Inherited注解的作用是:使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解)。
/**
* Indicates that an annotation type is automatically inherited. If
* an Inherited meta-annotation is present on an annotation type
* declaration, and the user queries the annotation type on a class
* declaration, and the class declaration has no annotation for this type,
* then the class's superclass will automatically be queried for the
* annotation type. This process will be repeated until an annotation for this
* type is found, or the top of the class hierarchy (Object)
* is reached. If no superclass has an annotation for this type, then
* the query will indicate that the class in question has no such annotation.
*
* <p>Note that this meta-annotation type has no effect if the annotated
* type is used to annotate anything other than a class. Note also
* that this meta-annotation only causes annotations to be inherited
* from superclasses; annotations on implemented interfaces have no
* effect.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
通过代码来进行验证,创建一个自定义注解
@Target({ElementType.TYPE})
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyInherited {
}
验证
@MyInherited
public class A {
public static void main(String[] args) {
System.out.println(A.class.getAnnotation(MyInherited.class));
System.out.println(B.class.getAnnotation(MyInherited.class));
System.out.println(C.class.getAnnotation(MyInherited.class));
}
}
class B extends A{
}
class C extends B{
}
执行main方法,从控制台中可以看到打印的信息
@Repeatable注解
重复注解:即允许在同一申明类型(类,属性,或方法)前多次使用同一个类型注解。
/**
* The annotation type {@code java.lang.annotation.Repeatable} is
* used to indicate that the annotation type whose declaration it
* (meta-)annotates is <em>repeatable</em>. The value of
* {@code @Repeatable} indicates the <em>containing annotation
* type</em> for the repeatable annotation type.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the <em>containing annotation type</em> for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class<? extends Annotation> value();
}
在java8 以前,同一个程序元素前最多只能有一个相同类型的注解;如果需要在同一个元素前使用多个相同类型的注解,则必须使用注解“容器”。 java8之前的做法
public @interface Roles {
Role[] roles();
}
public @interface Roles {
Role[] value();
}
public class RoleAnnoTest {
@Roles(roles = {@Role(roleName = "role1"), @Role(roleName = "role2")})
public String doString(){
return "";
}
}
java8之后增加了重复注解,使用方式如下:
public @interface Roles {
Role[] value();
}
@Repeatable(Roles.class)
public @interface Role {
String roleName();
}
public class RoleAnnoTest {
@Role(roleName = "role1")
@Role(roleName = "role2")
public String doString(){
return "";
}
}
不同的地方是,创建重复注解 Role 时,加上@Repeatable,指向存储注解 Roles,在使用时候,直接可以重复使用 Role 注解。从上面例子看出,java 8里面做法更适合常规的思维,可读性强一点。但是,仍然需要定义容器注解。
两种方法获得的效果相同。重复注解只是一种简化写法,这种简化写法是一种假象:多个重复注解其实会被作为“容器”注解的 value 成员的数组元素处理。
@Native注解
/**
* Indicates that a field defining a constant value may be referenced
* from native code.
*
* The annotation may be used as a hint by tools that generate native
* header files to determine whether a header file is required, and
* if so, what declarations it should contain.
*/
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Native {
}
类型注解
Java8 为 ElementType 枚举增加了TYPE_PARAMETER、TYPE_USE两个枚举值,从而可以使用 @Target(ElementType_TYPE_USE) 修饰注解定义,这种注解被称为类型注解,可以用在任何使用到类型的地方。
在 java8 以前,注解只能用在各种程序元素(定义类、定义接口、定义方法、定义成员变量…)上。从 java8 开始,类型注解可以用在任何使用到类型的地方。
TYPE_PARAMETER:表示该注解能写在类型参数的声明语句中。
TYPE_USE:表示注解可以再任何用到类型的地方使用,比如允许在如下位置使用:
-
创建对象(用 new 关键字创建)
-
类型转换
-
使用 implements 实现接口
-
使用 throws 声明抛出异常
public class TypeUserTest {
public static void main(String[] args) { String str = "str"; Object obj = (@isNotNull Object) str; }}
@Target(ElementType.TYPE_USE) @interface isNotNull{ }
这种无处不在的注解,可以让编译器执行更严格的代码检查,从而提高程序的健壮性。
作者:爱西考的王同学
链接:juejin.cn/post/684490…
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。