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