参考答案
1. @Repeatable注解的作用
JDK8 中增加了@Repeatable注解,是为解决同一个注解不能重复在同一类、方法、属性上使用的问题。
2. @Repeatable注解的使用场景
举一个比较贴近开发的例子,在spring、springboot引入资源文件,可以使用注解@PropertySource。
@PropertySource("classpath:sso.properties") public class Application { }
把PropertySource中的value设置成String[]数组,引入多个资源文件。
public @interface PropertySource { ... String[] value(); }
@PropertySource({"classpath:sso.properties","classpath:dubbo.properties","classpath:systemInfo.properties"}) public class Application { }
只是spring引入配置文件没有问题,如果注解中2个值存在依赖关系就不行了。例如:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) //@Repeatable(Validates.class) public @interface Validate { /** * 业务类型 * @return */ String bizCode(); /** * 订单类型 * @return */ int orderType(); }
上面的@validate注解,bizcode和orderType是一对一的关系,我希望可以添加注解:
@Validate(bizCode = "fruit",orderType = 1) @Validate(bizCode = "fruit",orderType = 2) @Validate(bizCode = "vegetable",orderType = 2) public class BizLogic2 { }
在java8之前,这种方式不行,但可以新建注解:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented public @interface Validates { Validate[] value(); }
注意:这个聚合注解默认约束value,以便存储子注解。
对应代码修改:
@Validates(value = { @Validate(bizCode = "fruit",orderType = 1) @Validate(bizCode = "fruit",orderType = 2) @Validate(bizCode = "vegetable",orderType = 2) }) public class BizLogic2 { }
在java8推出@Repeatable之后,不改动@Validates的情况下,对@Validate进行修改,增加@Repeatable(Validates.class),就可以在类上使用多个@Validate注解了。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(Validates.class) public @interface Validate { /** * 业务类型 * @return */ String bizCode(); /** * 订单类型 * @return */ int orderType(); }
再来看下,@PropertySource 和 @PropertySources都是这样。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(PropertySources.class) public @interface PropertySource /** * Container annotation that aggregates several {@link PropertySource} annotations. * * <p>Can be used natively, declaring several nested {@link PropertySource} annotations. * Can also be used in conjunction with Java 8's support for <em>repeatable annotations</em>, * where {@link PropertySource} can simply be declared several times on the same * {@linkplain ElementType#TYPE type}, implicitly generating this container annotation. * * @author Phillip Webb * @since 4.0 * @see PropertySource */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface PropertySources
上述注释中可见,spring的4.0支持Java8这个特性。
3. @Repeatable注解的原理
@Repeatable的原理,是语法糖。
反编译下面代码:
/*@Validates(value = {*/ @Validate(bizCode = "fruit",orderType = 1) @Validate(bizCode = "fruit",orderType = 2) @Validate(bizCode = "vegetable",orderType = 2) /*})*/ public class BizLogic2 { }
结果:
再反编译下面代码试试:
/*@Validates(value = {*/ @Validate(bizCode = "fruit",orderType = 1) // @Validate(bizCode = "fruit",orderType = 2) //@Validate(bizCode = "vegetable",orderType = 2) /*})*/ public class BizLogic2 { }
结果:
问题出现了,我以为添加@Repeatable之后,@Validate都会生成被语法糖@Validates包裹。没想到它很智能,只有一个@Validate注解时不转换。
所以使用多个@Validate时,要提前留坑,需要兼容1个或多个的场景。
感兴趣的童鞋可以测试下~
以上,是Java面试题【@Repeatable注解的作用】的参考答案。
输出,是最好的学习方法。
欢迎在评论区留下你的问题、笔记或知识点补充~
—end—