Как получить класс <T> из списка <T>
Я чувствую себя совершенно глупо, когда мне нужно это задавать, но я не понимаю, почему не компилируется следующий код Java:
void <T> doSomething(List<T> items) {
Class<? extends T> clazz = items.get(0).getClass();
...
}
Из документа Java:
Фактическим типом результата является класс <? расширяет | X | > где | X | это стирание статического типа выражения, на котором getClass называется. Например, в этом фрагменте кода не требуется бросок:
Число n = 0; Класс <? extends Number > c = n.getClass();
EDIT:
-
Нашел это приятное объяснение о том, что означает стирание статического типа.
-
Есть способ сохранить информацию об общем типе с использованием подклассов, называемых маркером супер-типа. Теперь удаленный ответ полезным образом отметил, что в библиотеке Guava есть удобная утилита для использования этого.
-
Здесь отличная статья о том, чтобы извлечь обобщенные типы рефлексивно и красивую lib, называемую GenTyRef, упрощая его
-
Я разблокировал GenTyRef, чтобы добавить поддержку для работы с AnnotatedType
(введено в Java 8). Он называется GenAnTyRef (и это в Maven Central)
Ответы
Ответ 1
Стирание статического типа items.get(0)
равно Object
(поскольку T
стирается во время компиляции).
Следовательно, items.get(0).getClass()
возвращает a Class<? extends Object>
, а не Class<? extends T>
, что объясняет, почему ваша попытка назначения не выполняется.
Это приведет к компиляции:
Class<? extends Object> clazz = items.get(0).getClass();
Если вы хотите, чтобы Class
общего параметра был известен этим методом, вы можете передать его в качестве дополнительного аргумента.
void doSomething(List<T> items, Class<T> clazz) {
}
Ответ 2
Прежде всего, вам нужно определить T как параметр типа для метода: <T> void doSomething
. Затем вам нужно сделать тэг Class<? extends T>
. Итак, вот как вы можете объединить:
<T> void doSomething(List<T> items) {
Class<? extends T> clazz = (Class<? extends T>) items.get(0).getClass();
...
}