浅析 java
中的可重复注解(Repeatable Annotation
)是如何实现的
要点
使用可重复注解时,总是需要定义对应的 containing annotation
。
假设我们定义了可重复注解 A
,而它的 containing annotation
是 CA
。
- 如果在类
C
上使用了可重复注解A
(且它的@Rentetion
的value
是RetentionPolicy.RUNTIME
),那么- 在
C.class
中会有RuntimeVisibleAnnotations
属性 CA
会出现在这个RuntimeVisibleAnnotations
属性中CA
中会有若干A
出现
- 在
正文
JDK 8
支持可重复注解(Repeatable Annotation
)。在 Java Language Specification 中的 9.6.3. Repeatable Annotation Interfaces 小节 提到
An annotation interface A is repeatable if its declaration is (meta-)annotated with an
@Repeatable
annotation (§9.6.4.8) whosevalue
element indicates a containing annotation interface of A.
大意是说,一个注解 A
是可重复注解,如果 A
上有 @Repeatable
元注解且 @Repeatable
的 value
的值是 A
的一个 containing annotation
。
例子
使用可重复注解的例子
我写了一个简单的例子,请将以下代码保存为 PrimeNumber.java
⬇️
java
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Sample(value = 2)
@Sample(value = 3)
@Sample(value = 5)
@Sample(value = 7)
public class PrimeNumber {
public static void main(String[] args) throws NoSuchMethodException {
// 下面这行的 sample 会是 null
Sample sample = PrimeNumber.class.getAnnotation(Sample.class);
System.out.println(sample == null);
// 下面这行的 samples 中会有 4 个元素
Sample[] samples = PrimeNumber.class.getAnnotationsByType(Sample.class);
System.out.println(samples.length);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Samples.class)
@interface Sample {
int value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface Samples {
Sample[] value();
}
这里的 @Sample
注解是可重复注解,而 Samples
是对应的 containing annotation
。
以下命令可以编译 PrimeNumber.java
并运行其中的 main(...)
方法。
bash
javac PrimeNumber.java
java PrimeNumber
运行结果如下 ⬇️
text
true
4
在编译之后,我们会得到 PrimeNumber.class
文件,用以下命令可以查看 PrimeNumber.class
的内容 ⬇️
css
javap -v -p PrimeNumber
完整的结果有点长,结尾部分的内容如下 ⬇️
text
RuntimeVisibleAnnotations:
0: #51(#52=[@#53(#52=I#54),@#53(#52=I#55),@#53(#52=I#56),@#53(#52=I#57)])
Samples(
value=[@Sample(
value=2
),@Sample(
value=3
),@Sample(
value=5
),@Sample(
value=7
)]
)
从中可以看出,在 RuntimeVisibleAnnotations
这个属性中,保存的是 @Samples
注解(这个注解中包含了 4
个 @Sample
注解)。
显式使用 containing annotation
的例子
我们也可以直接使用 @Samples
注解。 请将以下代码保存为 PrimeNumber2.java
java
@Samples(value = {
@Sample(value = 2),
@Sample(value = 3),
@Sample(value = 5),
@Sample(value = 7)
})
public class PrimeNumber2 {
}
用以下命令可以编译 PrimeNumber2.java
bash
javac PrimeNumber2.java
编译后,我们会得到 PrimeNumber2.class
文件,用以下命令可以查看 PrimeNumber.class
的内容 ⬇️
css
javap -v -p PrimeNumber2
完整的结果有点长,结尾部分的内容如下 ⬇️
text
RuntimeVisibleAnnotations:
0: #14(#15=[@#16(#15=I#17),@#16(#15=I#18),@#16(#15=I#19),@#16(#15=I#20)])
Samples(
value=[@Sample(
value=2
),@Sample(
value=3
),@Sample(
value=5
),@Sample(
value=7
)]
)
这里的 RuntimeVisibleAnnotations
属性的内容,和 PrimeNumber.class
中 RuntimeVisibleAnnotations
属性的内容是一致的。由此可见,以下两种情况在 class
中的表示方式是一致的
- 直接使用可重复注解
- 显式使用可重复注解的
containing annotation