为了理解Java注释,我尝试了一些并且几乎没有怀疑,即使看着执行我仍然感到困惑。这就是我在做的事情。 定义注释
@Retention(RetentionPolicy.CLASS)
@Target(value=ElementType.TYPE)
public @interface Command {
}
现在我初始化命令
Reflections reflections = new Reflections(CMDS_PACKAGE);
Set<Class<?>> allClasses = reflections.getTypesAnnotatedWith(Command.class); // line 2
for (Class clazz : allClasses) {
MYCommand cmd = (MYCommand) clazz.newInstance();
System.out.println(cmd.getClass().getAnnotation(Command.class));// line 6
log.info("loading Command [ {} ]", clazz.getCanonicalName());
}
当我运行程序行6时显示null
。
当策略为RetentionPolicy.RUNTIME
时,第6行显示正确的命令。
在此过程中,无论政策如何,第2行仍然给我正确的注释类。那么它是否意味着反射Library忽略了RetentionPolicy
即使阅读了大部分教程,我也很困惑。
我的问题实际上是,为什么这种不同的行为?用RetentionPolicy.CLASS
策略注释它不应该在运行时给我。我的理解是错误的还是任何人都可以分享对这两者的理解的宝贵意见。
答案 0 :(得分:0)
首先,RetentionPolicy
指示一致的编译器必须做什么。 Annotation
RetentionPolicy.SOURCE
RetentionPolicy.CLASS
不会将其放入类文件中,而其他两个RetentionPolicy.RUNTIME
和RetentionPolicy
存储在类文件中,但使用不同的属性允许在阅读类文件时区分它们。
documentation of RetentionPolicy.CLASS
说:
注释将由编译器记录在类文件中,但在运行时不需要由VM保留。这是默认行为。
此处,责任明确记录在案, VM 不得保留它们,并且内置于JRE中的Reflection API符合它。虽然“不需要保留”并不是一个强烈的要求。
但是,您使用的Reflection Library之类的第三方库可以在解析类文件时自由实现他们想要的任何内容。由于您调用的方法的文档只是简单地说:“获取使用给定注释注释的类型”,因为类型具有该注释,行为没有错误。
通过分析Annotation
的{{1}},您甚至可以在调用该方法之前找到Annotations
的{{1}}。因此,当您已经知道注释具有Annotation
然后烦恼时调用该方法是没有意义的,因为该方法执行某些操作而不是任何操作。
但是,当然,如果完全记录这种行为会更好。因此,您可能会要求第三方库的作者改进文档。
答案 1 :(得分:0)
是的,默认情况下,Reflections library(不是反射,但反射* s *)会忽略注释的可见性。 可以使用org.reflections.adapters.JavassistAdapter#includeInvisibleTag标志更改此设置。类似的东西:
JavassistAdapter mdAdapter = new JavassistAdapter();
mdAdapter.includeInvisibleTag = false;
new Reflections(new ConfigurationBuilder()
...
.setMetadataAdapter(mdAdapter)
...
另一种选择是使用JavaReflectionAdapter。
HTH