具有类型参数的批注属性

2022-09-01 06:00:39

定义 Java 接口时,可以使用类型参数声明方法,例如:

public interface ExampleInterface {
    <E extends Enum<E>> Class<E> options();
}

同样的事情在注释中不起作用。例如,这是非法的:

public @interface ExampleAnnotation {
    <E extends Enum<E>> Class<E> options();
}

我可以通过使用原始类型来获得我所追求的:Enum

public @interface ExampleAnnotation {
    @SuppressWarnings("rawtypes")
    Class<? extends Enum> options();
}

究竟是什么原因导致无法使用类型参数声明注释属性?


答案 1

我认为这是可能的,但它需要对语言规范进行大量添加,这是不合理的。

首先,对于枚举示例,您可以使用 .Class<? extends Enum<?>> options

还有另一个问题:既然是 a that is a ,那么Class<? extends Enum> optionsEnum.classClass<Enum>Class<? extends Enum>options=Enum.class

这不会发生在 ,因为 不是 的子类型,在凌乱的原始类型治疗中,这是一个相当偶然的事实。Class<? extends Enum<?>> optionsEnumEnum<?>

回到一般问题。由于在有限的属性类型中,是唯一具有类型参数的属性类型,并且通配符通常具有足够的表现力,因此您的问题不太值得解决。Class

让我们进一步概括这个问题,假设有更多的属性类型,并且通配符在许多情况下不够强大。例如,假设是允许的,例如Map

Map<String,Integer> options();

options={"a":1, "b":2} // suppose we have "map literal"

假设我们希望 attrbite 类型适用于任何类型 。这不能用通配符来表示 - 意味着任何.Map<x,x>xMap<?,?>Map<x,y>x,y

一种方法是允许类型具有类型参数:。这实际上在一般情况下非常有用。但这是类型系统的重大变化。<X>Map<X,X>

另一种方法是重新解释批注类型中方法的类型参数。

<X> Map<X,X> options();

options={ "a":"a", "b":"b" }  // infer X=String

这在当前对方法类型参数,推理规则,继承规则等的理解中根本不起作用。我们需要改变/添加很多东西才能使它工作。

无论哪种方法,如何交付给注释处理器都是一个问题。我们必须发明一些额外的机制来携带带有实例的类型参数。X


答案 2

Java™语言规范第三版说:

由于注解类型声明的上下文无关语法,对它们施加了以下限制:

  • 批注类型声明不能是泛型的。
  • 不允许使用扩展条款。(批注类型隐式扩展批注。注释。
  • 方法不能有任何参数
  • 方法不能有任何类型参数
  • 方法声明不能具有 throws 子句

推荐