自定义注解 Java

恰逢最近有机会用到自定义注解,整理最近学习到的知识在这里做一个持久化输出。

1.自定义注解介绍

1.使用@interface声明一个注解类
3.自定义注解时,需要使用元注解。官方提供的注解有以下几种:

基本注解元注解(修饰其它注解)
所属包:java.lang所属包:java.lang.annotation
@Override@Retention
@Deprecated@Target
@SuppressWarnings@Documented
@FunctionalInterface(1.8)@Inherited
@SafeVarargs@Repeatable (1.8)

简单介绍一下创建自定义注解时常用的注解:

1.1 @Target 表示该注解目标,可能的 ElemenetType 参数包括
  • ElemenetType.CONSTRUCTOR 构造器声明
  • ElemenetType.FIELD 域声明(包括 enum 实例)
  • ElemenetType.LOCAL_VARIABLE 局部变量声明
  • ElemenetType.METHOD 方法声明
  • ElemenetType.PACKAGE 包声明
  • ElemenetType.PARAMETER 参数声明
  • ElemenetType.TYPE 类,接口(包括注解类型)或enum声明
1.2 @Retention 表示该注解的生命周期,可选的 RetentionPolicy 参数包括
  • RetentionPolicy.SOURCE 注解将被编译器丢弃
  • RetentionPolicy.CLASS 注解在class文件中可用,但会被JVM丢弃
  • RetentionPolicy.RUNTIME JVM将在运行期也保留注释,因此可以通过反射机制读取注解的信息
1.3 @Inherited 使注解具有继承性。子类会带有父类中被@Inherited修饰的注解。
1.4 @Documented 指示将此注解包含在 javadoc 中
1.5 @Repeatable 想在一处同时使用多个相同的注解时,需要新建数组注解类,并在原注解类上使用@Repeatable声明数组注解类。此时通过反射获取多个相同注解的时候,得到的是一个数组注解类,而不是多个原注解类。

这一段比较复杂,使用一个例子说明。首先定义一个注解类:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    String key();
    String value();
}

此时想使用多个该注解时会报错

@TestAnnotation(key = "key1",value = "value1")
@TestAnnotation(key = "key2",value = "value2")//该行报错,错误信息见下行
//Duplicate annotation. The declaration of 'TestAnnotation' does not have a valid
//java.lang.annotation.Repeatable annotation
public class Person {
    private String name;
}

想要修复这个报错需要两步,1.新建该注解的数组注解类,2.对TestAnnotation注解添加@Repeatable。

  1. 新建一个数组注解类如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestArrayAnnotation {
    TestAnnotation[] value();
}
  1. 修改TestAnnotation注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TestArrayAnnotation.class)//添加这行代码
public @interface TestAnnotation {
    String key();
    String value();
}

这时就大功告成了。使用反射获取一下我们添加的注解信息:

public class Test {
    public static void main(String[] args) {
        Class clazz = Person.class;
        Annotation[] annotations = clazz.getAnnotations();
        System.out.println(annotations.length + " | " + Arrays.toString(annotations));
        Annotation[] annotationsByType = clazz.getDeclaredAnnotationsByType(TestAnnotation.class);
        System.out.println(annotationsByType.length + " | " + Arrays.toString(annotationsByType));
    }
}

执行后,输出结果为:

1 | [@com.business.TestArrayAnnotation(value={@com.business.TestAnnotation(key="key1", value="value1"), @com.business.TestAnnotation(key="key2", value="value2")})]
2 | [@com.business.TestAnnotation(key="key1", value="value1"), @com.business.TestAnnotation(key="key2", value="value2")]

需要注意两种方法获取到的对象不同,下面会讲到。
此外在定义TestArrayAnnotation时,生命周期@Retention和可修饰范围@Target都要比TestAnnotation注解的要大。否则在使用多个TestAnnotation注解时会因为找不到对应的数组注解 类而报错。

2.自定义注解获取

获取类、字段、方法上对应的注解:

public class Test {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
        Class clazz = Person.class;
        Annotation[] clazzAnnotations = clazz.getAnnotations();//类注解
        Method method = clazz.getMethod("getName");
        Annotation[] methodAnnotations = method.getAnnotations();//方法注解
        Field field = clazz.getField("name");
        Annotation[] fieldAnnotations = field.getAnnotations();//字段注解
    }
}
注意事项

反射获取注解时要使用对应的方法,下面会做介绍。
引用自java 获取注解信息的方法 小结

对于获取注解时,有4种情况:

Directly Present直接存在注解直接修饰
Indirectly Present间接存在注解直接修饰并且该注解被@Repeatable 修饰
Present存在注解直接修饰/来自父类的注解
Associated关联直接或间接存在/父类直接或间接存在

反射方法和获取对应的关系:

MethodDirectly PresentIndirectly PresentPresentAssociated
T getDeclaredAnnotation(Class)X
Annotation[] getDeclaredAnnotations()X
T[] getDeclaredAnnotationsByType(Class)XX
T getAnnotation(Class)X
Annotation[] getAnnotations()X
T[] getAnnotationsByType(Class)X

虽然有四种关系,实际上都是基于两种关系(直接存在,间接存在)推演的。

MethodDirectly PresentIndirectly Presentinherit Directly Presentinherit Indirectly Present
T getDeclaredAnnotation(Class)X
Annotation[] getDeclaredAnnotations()X
T[] getDeclaredAnnotationsByType(Class)XX
T getAnnotation(Class)XX
Annotation[] getAnnotations()XX
T[] getAnnotationsByType(Class)XXXX

命名规则对应关系:

  • getDeclaredAnnotationXXXX :只可以获取直接存在注解信息
  • getXXXXByType : 可以获取间接存在注解信息
  • getAnnotationXXX : 可以获取继承注解信息
  • 所有的方法都可以获取直接注解信息

3.注解原理

本人能力有限,看到这篇写的非常不错,推荐给大家- Java注解(Annotation)原理详解

参考链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值