Атрибуты аннотации с параметрами типа - PullRequest
26 голосов
/ 29 сентября 2011

Когда вы определяете интерфейс 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();
}

В чем именно причина, по которой невозможно объявить атрибуты аннотации с параметрами типа?

Ответы [ 4 ]

18 голосов
/ 29 сентября 2011

Я думаю, что это возможно, но требует множества дополнений к спецификации языка, что неоправданно.

Во-первых, для примера enum вы можете использовать Class<? extends Enum<?>> options.

В Class<? extends Enum> options есть еще одна проблема: поскольку Enum.class является Class<Enum>, то есть Class<? extends Enum>, допустимо options=Enum.class

Этого не может случиться с Class<? extends Enum<?>> options, потому что Enum не является подтипом Enum<?>, что является довольно случайным фактом в беспорядочных обработках необработанных типов.

Вернемся к общей проблеме. Поскольку среди ограниченных типов атрибутов Class является единственным с параметром типа, а подстановочный знак обычно достаточно выразителен, ваша проблема не стоит того, чтобы ее затрагивать.

Давайте обобщим проблему еще больше, предположим, что есть больше типов атрибутов, и во многих случаях подстановочный знак недостаточно силен. Например, допустим, что Map разрешено, например,

Map<String,Integer> options();

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

Предположим, мы хотим, чтобы тип attrbite был Map<x,x> для любого типа x. Это нельзя выразить с помощью подстановочных знаков - Map<?,?> означает скорее Map<x,y> для любого x,y.

Один из подходов - разрешить параметры типа для типа: <X>Map<X,X>. Это на самом деле довольно полезно в целом. Но это серьезное изменение в системе типов.

Другой подход заключается в переинтерпретации параметров типа для методов в типе аннотации.

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

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

это не работает вообще в текущем понимании параметров типа метода, правил вывода, правил наследования и т. Д. Нам нужно изменить / добавить много вещей, чтобы это работало.

При любом подходе проблема состоит в том, чтобы доставить X процессорам аннотаций. Придется придумать какой-то дополнительный механизм для переноса аргументов типа с экземплярами.

11 голосов
/ 29 сентября 2011

Третье издание спецификации языка Java ™ гласит:

Следующие ограничения налагаются на объявления типов аннотаций в силу их контекстно-свободный синтаксис :

  • Объявления типов аннотаций не могут быть общими.
  • Не допускается расширение выражений. (Типы аннотаций неявно расширяют аннотации. Аннотация.)
  • Методы не могут иметь никаких параметров
  • Методы не могут иметь параметры типа
  • Объявления методов не могут содержать предложение throws
7 голосов
/ 30 сентября 2011

Раздел 9.6 Спецификации языка Java описывает аннотации. Одно из предложений там гласит:

Ошибка времени компиляции, если тип возвращаемого значения метода, объявленного в типе аннотации, является любым типом, отличным от одного из следующих: один из примитивных типов, String, Class и любой вызов Class, тип enum (§8.9), тип аннотации или массив (§10) одного из предыдущих типов. Также ошибка времени компиляции, если какой-либо метод, объявленный в типе аннотации, имеет сигнатуру, эквивалентную переопределению, сигнатуре любого открытого или защищенного метода, объявленного в классе Object или в аннотации интерфейса. Аннотация.

А потом говорится следующее, что, я думаю, является ключом к этой проблеме:

Обратите внимание, что это не противоречит запрету на обобщенные методы, поскольку подстановочные знаки устраняют необходимость в явном параметре типа.

Так что это говорит о том, что я должен использовать подстановочные знаки, а параметры типа не нужны. Чтобы избавиться от необработанного типа Enum, мне просто нужно использовать Enum<?>, как неопровержимо предложено в его ответе:

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

Вероятно, разрешение параметров типа открыло бы банку червей, так что разработчики языка решили просто запретить их, так как вы можете получить то, что вам нужно с подстановочными знаками.

4 голосов
/ 29 сентября 2011

Они хотели ввести аннотации, чтобы люди могли использовать их только как аннотации.И не позволяйте разработчикам вкладывать в них логику.то есть начать программирование с использованием аннотаций , что, на мой взгляд, может сделать Java похожим на совершенно другой язык.Следовательно, контекстно-свободный синтаксис примечание в спецификации языка Java.

Следующие ограничения налагаются на объявления типов аннотаций в силу их контекстно-свободного синтаксиса :

Annotation type declarations cannot be generic.
No extends clause is permitted. (Annotation types implicitly extend annotation.Annotation.)
Methods cannot have any parameters
Methods cannot have any type parameters

(http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html)

Чтобы лучше понять, что я имею в виду, посмотрите, что делает этот хакер JVM: http://www.cs.rice.edu/~mgricken/research/xajavac/

Он создает И, Или аннотации в виде инструкций и обработка других аннотаций с их использованием. Бесценно!

...