注释中的通用类型

Obi*_*ere 5 java generics annotations

考虑以下代码:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class AnnotationTest {

    @GenericAnnotation<String>(foo = "Test")
    public class Bar1 {

    }

    @ObjectAnnotation(foo = "Test")
    public class Bar2 {

    }

    @WorkingAnnotation(foo = "Test")
    public class Bar3 {

    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface GenericAnnotation<T> {

        public T foo();

    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface ObjectAnnotation {

        public Object foo();

    }

    @Retention(RetentionPolicy.RUNTIME)
    public @interface WorkingAnnotation {

        public String foo();

    }

}
Run Code Online (Sandbox Code Playgroud)

Bar1根本不会编译。一大堆错误。

Bar2会编译正常,但ObjectAnnotation注释不会。

Bar3 将编译良好,但不允许泛型类型。


如果 - 例如 - 我试图设置一个默认值,以防某个字段无法加载。此类可能是Integer, String, Boolean[],实际上是任何可能的类型。这意味着处理每一种可能情况的注释都是一团糟。


是否有正确的方法来处理注释中的泛型类型?如果没有,是否有明确的原因?

Ado*_*ath 4

编译器的错误消息令人困惑,纯粹是因为它没有接受这样的语法。

\n

类似的问题已经发布在这里

\n

情况1

\n

JLS第 9.6 节规定了注释声明的一般语法,如下所示:

\n
\n

注释类型声明:

\n
{InterfaceModifier} @ interface Identifier AnnotationTypeBody\n
Run Code Online (Sandbox Code Playgroud)\n
\n

令牌标识符,用JLS的术语来说,描述了类型的名称;无论是类、枚举、接口还是注释。

\n

不能使用泛型类型声明注释,因为这些类型由标记TypeParameters引用,此处未包含该标记。

\n

至于为什么,这会导致

\n

案例2

\n

查看下一项,第 9.6.1 节,我们发现注释可以采用的类型的限制:

\n
\n

注解类型中声明的方法的返回类型必须是以下类型之一,否则会出现编译时错误:

\n
    \n
  • 原始类型
  • \n
  • 细绳
  • \n
  • 类或类的调用 (\xc2\xa7 4.5 )
  • \n
  • 枚举类型
  • \n
  • 注释类型
  • \n
  • 其组件类型为上述类型之一的数组类型 (\xc2\xa7 10.1 )。
  • \n
\n
\n

(一些特殊情况将在下面进一步讨论,但与此问题无关)

\n

这些限制是导致您对第二个注释感到沮丧的原因。它根本无法容纳所有类型的对象。它甚至不能容纳原语的盒装类型!

\n

现在,回到案例 1:为什么通用注释在这个语法中是错误的?即使在发生任何类型擦除之前,您的 GenericAnnotation 基本上可以成为每种类型的对象的持有者。在其foo属性的定义中,它与您的ObjectAnnotation完全相同。

\n

现在的问题是,为什么会有这样的限制?通过限制注释可能包含的值,您可以获得两个优点:首先,所有值都是编译时常量。如果不大量使用反射,就无法将依赖于运行时的值放入或取出注释。

\n

这立即带来了第二个优点:没有人会受到诱惑将不纯的(副作用)代码放入注释中,这些注释可能在应用程序生命周期中的任何随机点加载。如果您可以引入任何类型的对象,它们的构造函数可能会在可能无法检测到的时间产生任何类型的副作用,如果使用此技术,则会增加调试的复杂性。

\n

或者至少,这对我来说似乎是最合乎逻辑的,因为我找不到 Sun 或其继任者对此的官方说法。

\n

可能的解决方法:无

\n

遗憾的是,对此没有简单、富有表现力且容易的解决方法。 \n由于您无法将进程放入 @Annotation-uses 中,因此您甚至无法做一些奇特的事情,例如使用 ObjectOutputStream 和 ByteArrayOutputStream 将对象序列化为字节数组。

\n