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

Как получить класс <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)

4b9b3361

Ответ 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();
    ...
}