Атрибуты аннотации с параметрами типа
Когда вы определяете интерфейс 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
.
В 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 в качестве инструкций и обрабатывает другие аннотации, используя их. Бесценный!