1

为了理解 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 行仍然给我正确的 Annotated 类,而不管政策如何。那么这是否意味着反射忽略了RetentionPolicy

即使阅读了大多数教程,我也很困惑。

我的问题实际上是,为什么这是不同的行为?当用策略注释时RetentionPolicy.CLASS 它不应该在运行时给我。我的理解是否错误,或者任何人都可以分享对这两者的理解的宝贵意见。

4

2 回答 2

0

首先,它RetentionPolicy规定了符合标准的编译器必须做什么。AnnotationsRetentionPolicy.SOURCE不进入类文件,而其他两个RetentionPolicy.CLASSRetentionPolicy.RUNTIME存储在类文件中,但使用不同的属性以允许在读取类文件时区分它们。

文档RetentionPolicy.CLASS说:

注释将由编译器记录在类文件中,但不需要在运行时由 VM 保留。这是默认行为。

在这里,责任被清楚地记录下来,VM不应保留它们,并且 JRE 中内置的反射 API 符合它。尽管“不需要保留”听起来并不像一个强烈的要求。

但是,像您正在使用的反射库这样的第三方库在解析类文件时可以自由地实现他们想要的任何东西。由于您调用的方法的文档只是说:“获取使用给定注释注释的类型”,因此该行为没有错误,因为该类型具有该注释。

并且您甚至可以在RetentionPolicy调用Annotation该方法之前通过Annotations分析Annotation. 因此,当您已经知道注释具有时调用该方法是没有意义的RetentionPolicy.CLASS,然后会打扰,因为该方法做了一些事情而不是什么都不做。

但是,当然,如果完全记录该行为会更好。因此,您可能会要求该第 3 方库的作者改进文档。

于 2014-01-17T09:54:15.173 回答
0

是的,Reflections 库(不是 Reflection,而是 Reflection* s *)默认情况下会忽略注释的可见性。这可以使用 org.reflections.adapters.JavassistAdapter#includeInvisibleTag标志进行更改。就像是:

JavassistAdapter mdAdapter = new JavassistAdapter();
mdAdapter.includeInvisibleTag = false;

new Reflections(new ConfigurationBuilder()
    ...
    .setMetadataAdapter(mdAdapter)
    ...

另一种选择是改用 JavaReflectionAdapter。

高温高压

于 2014-01-20T09:49:56.410 回答