Передача класса с параметром типа в качестве параметра типа для универсального метода в Java



предупреждение:
Я хотел бы передать класс с параметром типа (например,ArrayList<SomeClass>, например) к универсальному методу в качестве параметра типа.



допустим, у меня есть метод:



    public static <T> T getGenericObjectFromJson(String json, Class<T> genericType){
// details unimportant, basically returns an object of specified type
return JsonParser.fromJson(json, genericType);
}


этот метод, конечно, будет отлично работать и для любого класса. Я могу вызвать метод так, например:



getGenericObjectFromJson(jsonString, User.class)


проблема: я обнаружил, что не могу этого сделать:



getGenericObjectFromJson(jsonString, ArrayList<User>.class)


синтаксически, это очевидно, недействительным. Однако я не уверен, как бы я даже сделал что-то подобное. Я могу, конечно, пройти ArrayList.class, однако добавление универсального типа больше не делает его синтаксически допустимым, и я не могу придумать способ обойти его.



единственным прямым решением было что-то вроде этого (что кажется довольно глупым):



getGenericObjectFromJson(jsonString, new ArrayList<User>().getClass())


однако мы все равно теряем общий тип и просто возвращаем ArrayList неизвестного типа (хотя это может быть отбрасывать.) Кроме того, излишне создавать экземпляр объекта.



мое единственное решение было обернуть этот метод в класс, который содержит параметр универсального типа, который может быть создан, например, так:

public class JsonDeserializer<T>...


в этом случае getGenericObjectFromJson метод будет использовать универсальный тип класса.



вопрос(ы): в конечном счете, мне любопытно, почему я не могу передать класс с параметром типа, и есть ли способ выполнить то, что я пытался делать.



как всегда, дайте мне знать, если есть какие-то проблемы с этим вопросом.

792   1  

1 ответ:

это на самом деле возможно в Java, используя некоторые "трюки". Не поддавайтесь давлению со стороны фанатиков C#! (j / k)

"трюк" состоит в том, чтобы создать класс, который расширяет универсальный тип, и получить доступ к значению параметра типа родительского класса через Type возвращено .getGenericSuperclass() или .getGenericInterfaces().

это довольно громоздко. Чтобы упростить нашу жизнь, Google уже написал большую часть скучной части кода для нас и сделал его доступным через Гуава.

Регистрация TypeToken класс, который делает именно то, что вы хотите. Например:

TypeToken<List<String>> stringListTok = new TypeToken<List<String>>() {};

затем вы проходите вокруг TypeToken<T> вместо Class<T> и это все. Он предоставляет вам методы для отражения типа, представленного T.

то, что это делает внутренне, просто вызывает .getClass().getGenericSuperclass() (или ...Interfaces()), то некоторые уродливые слепки с Type to ParameterizedType и получение всей информации оттуда (.getActualTypeArguments(), etc).

наконец, если вы хотите сделать что-то подобное с инъекцией зависимостей (т. е. предположим, что вам нужно ввести Class<T> на конструкторе класса, или вы хотите получить экземпляр некоторого параметризованного интерфейса, в котором экземпляр должен зависеть от параметра типа), Google Guice (контейнер DI от Google) имеет очень похожий механизм для решения проблемы, называемый TypeLiteral. Использование и код за кулисами почти идентичны TypeToken от Гуава. Проверьте это здесь:TypeLiteral

Comments

    Ничего не найдено.