Подтвердить что ты не робот

Атрибуты аннотации с параметрами типа

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

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

4b9b3361

Ответ 1

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

Во-первых, для примера перечисления можно использовать 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"

Предположим, что для любого типа x тип attrbite должен быть Map<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 в обработчики аннотаций. Нам придется придумать дополнительный механизм для переноса аргументов типа с экземплярами.

Ответ 2

В спецификации третьего языка Java ™ указано:

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

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

Они хотели ввести аннотации, чтобы люди могли использовать их только как,, аннотации. И не позволяйте разработчикам вводить в них логику. т.е. начать программировать материал с помощью аннотаций, что может повлиять на то, что 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/

Он создает аннотации And, Or в качестве инструкций и обрабатывает другие аннотации, используя их. Бесценный!