ParameterizedType.getRawType() возвращает j.l.r.Type, а не Class <?>?
ParameterizedType parameterized =
(ParameterizedType) List.class.getMethod("iterator").getGenericReturnType();
Type raw = parameterized.getRawType();
ParameterizedType#getRawType()
возвращает a Type
, а не a Class<?>
(хотя я понимаю, что java.lang.Class
теперь реализует Type
). Есть ли веская причина, почему getRawType()
не объявляет свой тип возврата Class<?>
? Существуют ли экстремальные случаи, когда результат getRawType()
не может быть Class<?>
?
Это достаточно, чтобы работать с j.l.r.Type
как есть; это похоже на экземпляр, в котором они могли бы сэкономить нам одно понижение.
Ответы
Ответ 1
Он должен вернуть объект Class
, нет другого способа.
Почему? Кто знает, может быть, какой-то идеалистический уклон. Если он вернет Class
, это будет единственный вид Class
в новых интерфейсах Type
.
Реальная проблема заключается в смешении Class
и Type
. Ранее все типы представлены в Class
. Это было уже грязно, но все же терпимо. Было не так много типов.
В новых родовых типах они должны были разработать более чистую и истинно-специфицированную иерархию Type
, не зависящую от Class
. Вместо этого они включили Class
с Type
и создали больше беспорядка. Вся иерархия просто не имеет смысла. Любой новичок в этом вопросе и не знает об истории, будет потрясен этой ерундой.
Я бы не придавал дизайну Type
высокий стандарт. Например, ParameterizedType
определяет equals()
, но не hashCode()
. Там нет способа иметь две реализации ParameterizedType
работать в одной карте хэша. А подстановочный знак тоже типа? Ад нет.
И имя метода getRawType()
просто идиот. Это не имеет никакого отношения к raw type
. Он должен быть явно назван getClassOrInterface()
. Было бы слишком многословным? Посмотрите на getActualTypeArguments()
. (И да, он возвращает фактические аргументы! Не поддельные!)
Ответ 2
Реализация Sun ParameterizedType
определила метод getRawType()
для возврата Class<?>
. Поэтому он явно возвращает только Class<?>
Однако в моем пути к классам есть несколько других реализаций ParameterizedType
- из hibernate-validator, из aspectj, hibernate-annotations, jaxb. Некоторые из них возвращают Class<?>
, некоторые - Type
. Я не знаю, как они используются.
Ответ 3
Я думал об этом, и у меня есть догадка. Возможно, они хотели оставить возможность открытой для будущего сумасшествия, как это:
public class Z<L extends List<?>> {
L<Double> test;
}
Это не законный Java-код, но я думаю, он ясно, что это будет означать; new Z<ArrayList<?>>().test
будет иметь тип ArrayList<Double>
.
Если это было законно, ((ParameterizedType) test.getGenericType()).getRawType()
вернул бы TypeVariable
.
Ответ 4
Существуют и другие применения иерархии интерфейса типа, чем просто отражение api. Например, библиотека генерации кода может определять пользовательские реализации. Сам JDK 8 имеет 3 различные реализации WildcardType. Если ParameterizedType.getRawType() возвратил экземпляр класса, то вам нужно будет создать экземпляр класса, когда захотите.
Класс - это очень глубоко укоренившийся в JVM-тип, который привязывает привязку к памяти с собственным управлением. Чтобы создать экземпляр класса, вы должны иметь байтовый код, определяющий класс. Но в случае библиотеки генерации кода байт-код еще не существует. Если бы они потребовали, чтобы ParameterizedType возвращал класс, это ограничивало бы применимость иерархии интерфейса Type только к отражению api.
Это может показаться не очень сложным, но не является литой.
ParameterizedType.getOwnerType() возвращает тип, поскольку он сам может быть либо классом, либо другим параметризованным типом. Он теоретически может возвращать TypeVariable, поскольку справедливо следующее Java:
<M extends Map<?,?>> M.Entry<?,?> first(M map) { ... }
Однако он скомпилирован как статическая ссылка на стирание переменной типа, в этом случае M.Entry будет скомпилирован как Map.Entry. Вместо TypeVariable вызов getOwnerType() из api отражения будет классом, по крайней мере, согласно моим тестам.