У меня есть проблема с пониманием стирания стилей Java, когда речь идет о ограниченных типах. Учти это:
class Event {} // From the API
class FooEvent extends Event {}
abstract class Foo<EventType extends Event> {
public abstract <E extends EventType> void onEventCaught(E event);
}
class Bar extends Foo<FooEvent> {
@Override
public void onEventCaught(FooEvent event) {
}
}
По-видимому, это компилируется без проблем. Вопрос, который я задаю себе, - это то, для каких типов параметров объявлен Bar#onEventCaught()
, здесь (как в том, что думает отражение)?
Это onEventCaught(FooEvent event)
или возможно onEventCaught(Event event)
?
Стирание переменной типа (§4.4) является стиранием его левого края.
У тебя есть
<EventType extends Event>
а также
<E extends EventType>
Крайней левой границей E
является EventType
, которая является другой переменной типа, самой левой границей которой является Event
. Таким образом, стирание E
в
public abstract <E extends EventType> void onEventCaught(E event);
это Event
.
Переменные типа отображаются в файлах .class
, и вы можете использовать их в отражении.
Class<?> clazz = Foo.class;
TypeVariable typeVariable = clazz.getTypeParameters()[0];
Type type = typeVariable.getBounds()[0];
System.out.println(typeVariable);
System.out.println(type);
печать
EventType
class com.example.Event
@interface Subscribe
и кто-то просматривает класс с помощью отражения для методов с Subscribe
он увидит метод onEventCaught(Event event)
, это правильно?
Method#getParameterTypes
они увидят Event
. Если они используют Method#getParameters
который возвращает Parameter[]
, они увидят E
Хотя вы всегда можете найти, что такое E
с помощью некоторого обратного инжиниринга для переменных типа или класса метода.
class Foo<String>
но для этого классаString
будет представлять универсальный тип, а не типjava.lang.String
, поэтому вы не сможете использовать внутри негоString s = "hello world"
. Называть универсальные типы проще, например,class Foo<T>
.