Java注解之Repeatable解读

 更新时间:2023年06月15日 16:57:31   作者:蜡笔没了小新git  
这篇文章主要介绍了Java注解之Repeatable,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Java注解之Repeatable

Repeatable使用场景

在需要对同一种注解多次使用时,往往需要借助@Repeatable。

实例

在生活中一个人往往是具有多种身份,如果我把每种身份当成一种注解该如何使用???

先声明一个Persons类用来包含所有的身份

@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)
public   @interface Persons {
    Person[] value();
}

这里@Target是声明Persons注解的作用范围,参数ElementType.Type代表可以给一个类型进行注解,比如类,接口,枚举,注解。

@Retention是注解的有效时间,RetentionPolicy.RUNTIME是指程序运行的时候。

Person注解:

@Repeatable(Persons.class)
public  @interface Person{
    String role() default "";
}

@Repeatable括号内的就相当于用来保存该注解内容的容器。

声明一个Man类,给该类加上一些身份。

@Person(role="CEO")
@Person(role="husband")
@Person(role="father")
@Person(role="son")
public   class Man {
    String name="";
}

在主方法中访问该注解。

    public static void main(String[] args) {
        Annotation[] annotations = Man.class.getAnnotations();  
        System.out.println(annotations.length);
        Persons p1=(Persons) annotations[0];
        for(Person t:p1.value()){
            System.out.println(t.role());
        }
    }

下面的代码结果输出相同,但是可以先判断是否是相应的注解,比较严谨。 

if(Man.class.isAnnotationPresent(Persons.class)) {
    Persons p2=Man.class.getAnnotation(Persons.class);
    for(Person t:p2.value()){
        System.out.println(t.role());
    }
 }

运行结果:

1
CEO
husband
father
son

对@Repeatable的理解

@Repeatable是jdk8中新增的注解,使用如Spring中的@ComponentScan注解。

在没有@Repeatable注解的的注解中,在同一个地方使用相同的注解会报错,有了此元注解注解的注解,就可以在同一个地方使用相同的注解。

其官方文档如下:

The annotation type {@code java.lang.annotation.Repeatable} is used to indicate that the annotation type whose declaration it (meta-)annotates is repeatable.

The value of @Repeatable indicates the containing annotation type for the repeatable annotation type.

@Repeatable 注解是用于声明其它类型注解的元注解,来表示这个声明的注解是可重复的。

@Repeatable的值是另一个注解,其可以通过这个另一个注解的值来包含这个可重复的注解。

示例

Value注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String value() default "value";
}

Values注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Values {
    Value[] value();
}

其中,@Value注解上的元注解@Repeatable中的值,使用了@Values注解,@Values注解中包含的值类型是一个@Value注解的数组!

这就解释了官方文档中@Repeatable中值的使用。

测试

注解使用方法

public class AnnotationClass {
    @Value("hello")
    @Value("world")
    public void test(String var1, String var2) {
        System.out.println(var1 + " " + var2);
    }
}

测试用例

// 获取使用`@Value`注解的`test`方法,并打印这个方法上的注解长度和信息
    @Test
    public void testValue() {
        Method[] methods = AnnotationClass.class.getMethods();
        for (Method method : methods){
            if (method.getName().equals("test")) {
                Annotation[] annotations = method.getDeclaredAnnotations();
                System.out.println(annotations.length);
                System.out.println(method.getName() + " = " + Arrays.toString(annotations));
            }
        }
    }

因为test方法上使用了两个@Value注解,所以猜测打印注解长度为2,然后打印详情,可是结果并不同。

1
test = [@com.example.annotations.Values(value=[@com.example.annotations.Value(value=hello), @com.example.annotations.Value(value=world)])]

结果显示,test方法上的注解长度为 1 , 且打印信息为@Values注解,它的值包含了使用的两个注解。

因此可知在jdk8中,相同注解只是以集合的方式进行了保存,原理并没有变化。

注意事项

一些约束

@Repeatable 所声明的注解,其元注解@Target的使用范围要比@Repeatable的值声明的注解中的@Target的范围要大或相同,否则编译器错误,显示@Repeatable值所声明的注解的元注解@Target不是@Repeatable声明的注解的@Target的子集

// Value
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String value() default "value";
}
// Values
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Values {
    Value[] value();
}

错误提示信息:

编译错误提示信息

@Repeatable注解声明的注解的元注解@Retention的周期要比@Repeatable的值指向的注解的@Retention得周期要小或相同。

周期长度为 SOURCE(源码) < CLASS (字节码) < RUNTIME(运行)

// Value 注意 @Retention的值
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String value() default "value";
}
// Values
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
public @interface Values {
    Value[] value();
}

编译错误信息

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java并发之synchronized实现原理深入理解

    Java并发之synchronized实现原理深入理解

    这篇文章主要介绍了Java中synchronized实现原理详解,涉及synchronized实现同步的基础,Java对象头,Monitor,Mark Word,锁优化,自旋锁等相关内容,具有一定借鉴价值,需要的朋友可以参考下
    2021-08-08
  • 详解Java中日志跟踪的简单实现

    详解Java中日志跟踪的简单实现

    MDC​(Mapped Diagnostic Context,映射调试上下文)是 log4j​ 、logback及log4j2​ 提供的一种方便在多线程条件下记录日志的功能。本文将利用MDC实现简单的日志跟踪,需要的可以参考一下
    2022-08-08
  • javaWeb项目部署到阿里云服务器步骤详解

    javaWeb项目部署到阿里云服务器步骤详解

    本篇文章主要介绍了javaWeb项目部署到阿里云服务器步骤详解,非常具有实用价值,需要的朋友可以参考下
    2017-05-05
  • Maven插件的安装及使用

    Maven插件的安装及使用

    这篇文章主要介绍了Maven插件的安装及使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java中怎样处理空指针异常

    Java中怎样处理空指针异常

    程序中的变量是 null,就意味着它没有引用指向或者说没有指针。这时,我们对这个变量进行任何操作,都必然会引发空指针异常,本文主要介绍了Java中怎样处理空指针异常,感兴趣的可以了解一下
    2022-05-05
  • java设计模式之单例模式

    java设计模式之单例模式

    这篇文章主要为大家详细介绍了java设计模式之单例模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • SpringBoot单机限流的实现

    SpringBoot单机限流的实现

    在系统运维中, 有时候为了避免用户的恶意刷接口, 会加入一定规则的限流,本文主要介绍了SpringBoot单机限流的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • idea将maven项目改成Spring boot项目的方法步骤

    idea将maven项目改成Spring boot项目的方法步骤

    这篇文章主要介绍了idea将maven项目改成Spring boot项目的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Spring集成PageHelper的简单用法示例

    Spring集成PageHelper的简单用法示例

    这篇文章主要介绍了Spring集成PageHelper的简单用法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • IDEA下使用Spring Boot热加载的实现

    IDEA下使用Spring Boot热加载的实现

    本文主要介绍了IDEA下使用Spring Boot热加载的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06

最新评论