Java: how do I get a class literal from a generic type?
Java: как мне получить литерал класса из универсального типа?
Обычно я видел, как люди используют литерал класса следующим образом:
Class<Foo> cls = Foo.class;
Но что, если тип является универсальным, например List? Это работает нормально, но выдает предупреждение, поскольку List должен быть параметризован:
Class<List> cls = List.class
Так почему бы не добавить <?>? Ну, это вызывает ошибку несоответствия типов:
Class<List<?>> cls = List.class
Я полагал, что что-то подобное сработает, но это всего лишь обычная синтаксическая ошибка:
Class<List<Foo>> cls = List<Foo>.class
Как я могу получить Class<List<Foo>> статически, например, используя литерал класса?
Я мог бы использовать @SuppressWarnings("unchecked"), чтобы избавиться от предупреждений, вызванных непараметризованным использованием List в первом примере, Class<List> cls = List.class но я бы предпочел этого не делать.
Единственный экземпляр, где информация об универсальном типе сохраняется во время выполнения, - это with Field.getGenericType() при запросе членов класса с помощью отражения.
Почему нет литерала класса для конкретных параметризованных типов?
Потому что параметризованный тип не имеет точного представления типа среды выполнения.
Литерал класса обозначает Class объект, представляющий данный тип. Например, литерал класса String.class обозначает Class объект, представляющий тип String и идентичен Class объекту, который возвращается при вызове метода getClass для String объекта. Литерал класса можно использовать для проверки типов во время выполнения и для отражения.
Параметризованные типы теряют свои аргументы типа , когда они преобразуются в байтовый код во время компиляции в процессе , называемом стиранием типа . В качестве побочного эффекта удаления типа все экземпляры универсального типа используют одно и то же представление во время выполнения, а именно представление соответствующего необработанного типа . Другими словами, параметризованные типы не имеют собственного представления типа. Следовательно, нет смысла формировать литералы класса, такие как List<String>.class , List<Long>.class и List<?>.class , поскольку таких Class объектов не существует. Только необработанный тип List имеет Class объект, который представляет его тип среды выполнения. Он называется List.class.
Ответ 2
Литералов класса для параметризованных типов не существует, однако существуют объекты типа, которые правильно определяют эти типы.
Библиотека Google Gson определяет класс TypeToken, который позволяет просто генерировать параметризованные типы и использует его для спецификации объектов json со сложными параметризованными типами универсальным способом. В вашем примере вы бы использовали:
Я намеревался разместить ссылки на классы TypeToken и Gson javadoc, но Stack Overflow не позволяет мне размещать более одной ссылки, поскольку я новый пользователь, вы можете легко найти их с помощью поиска Google
Ответ 3
Вы можете управлять им с помощью двойного приведения :
Чтобы пояснить ответ клетуса, во время выполнения все записи универсальных типов удаляются. Универсальные типы обрабатываются только в компиляторе и используются для обеспечения дополнительной безопасности типов. На самом деле это просто сокращение, которое позволяет компилятору вставлять приведения типов в соответствующие места. Например, ранее вам нужно было выполнить следующее: