Вот является Java универсальным шаблоном:
public <T> T getResultData(Class<T> resultClass, other_args) {
...
return resultClass.cast(T-thing);
}
Типичный вызов похож:
DoubleBuffer buffer;
buffer = thing.getResultData(DoubleBuffer.class, args);
Я никогда не был в состоянии выяснить, как использовать этот шаблон чисто, когда желаемый тип возврата, сам, универсален. Быть 'конкретным', что, если функция как это хочет возвратиться Map<String,String>
? Так как Вы не можете получить объект класса для дженерика, конечно, единственная опция состояла бы в том, чтобы передать Map.class
, и затем Вам нужен бросок и @SuppressWarning
в конце концов.
Каждый заканчивает вызовом как:
Map<String, String> returnedMap;
returnedMap = thing.getResultData(Map.class, some_other_args);
Теперь каждый вернулся к необходимости в бросках и подавлению предупреждения.
Я предполагаю, что можно было взять что-то от java.lang.reflect.Type
семья вместо Class
, но это не особенно легко придумать. Это похоже:
class Dummy {
Map<String, String> field;
}
...
Type typeObject = Dummy.class.getField("field").getGenericType();
Учитывая это, вызванная функция могла извлечь базовый тип и использование это для кастинга или newInstance-луга, но фиктивного полевого бизнеса верные ужасные взгляды.
Обратите внимание, что функции как это не всегда звонят newInstance
. Очевидно, если они делают, они не должны звонить resultClass.cast
.
Это невозможно сделать в стандартном Java API. Тем не менее, существуют утилитные классы, которые могут получить Type
из общего класса. Например, в Google Gson (который конвертирует JSON в полноценный Javabeans и наоборот) есть класс TypeToken
. Вы можете использовать его следующим образом:
List<Person> persons = new Gson().fromJson(json, new TypeToken<List<Person>>() {}.getType());
Такая конструкция - это именно то, что вам нужно. Вы можете найти здесь исходный код, он также может оказаться полезным. Требуется только дополнительный метод getResultData()
, который может принимать Type
.
Ну, вот уродливый (частичный) раствор. Вы не можете параметризовать общий параметр, поэтому вы не можете записать
public <T<U,V>> T getResultData ...
, но вы можете вернуть параметризованную коллекцию, например, для набора
public < T extends Set< U >, U > T getResultData( Class< T > resultClass, Class< U > paramClass ) throws IllegalAccessException, InstantiationException {
return resultClass.newInstance();
}
, где вы могли бы избавиться от U-парама, если бы он существовал в сигнатуре класса.
.Да, я не думаю, что это возможно.
Представь себе этот сценарий. У вас есть файл с сериализованным объектом, который вы хотите прочитать. Если вы сделаете функцию универсальной, вы сможете использовать ее без гипса. Но допустим, что у вас есть карта, сериализованная в файл.
Когда вы десериализуете ее, нет способа узнать , какой тип оригинальной универсальной карты был. Что касается java, это просто карта
Я столкнулся с этим со списками, и это было раздражающе. Но в итоге я создал общий класс "конвертирования коллекции", который принимает коллекцию и "конвертер" (который может быть анонимным внутренним типом).
Затем, когда вы выполняете итерацию по преобразующей коллекции, каждый элемент отбрасывается. И это решило проблему с предупреждением. Просто избавиться от предупреждения - большая работа, но я не думаю, что это было основной причиной, по которой я придумал этот фреймворк. Также можно сделать более мощные вещи, например, взять коллекцию имён файлов, а потом написать конвертер, который загрузит данные в файл, или сделает запрос, или ещё что-нибудь.
Итак, если я правильно понял, что вы на самом деле пытаетесь сделать (незаконный псевдосинтаксис):
public <T, S, V> T<S, V> getResultData(Class<T<S, V>> resultClass, other_args) {
...
return resultClass.cast(T-thing);
}
Вы не можете, потому что вы не можете далее параметрировать тип generic T
. Сообщения с java.lang.reflect.*
не помогут:
Class
и, следовательно, нет способа динамически создать его экземпляр. T
Вы можете использовать TypeLiteral, если вы хотите использовать типизированные контейнерные классы. Они используются в Guice для обеспечения типовой безопасности. Дополнительные примеры см. в Guice Source code и в классе TypeLiteral.
Кстати, не нужно использовать кастинг, например, если вы вызываете resultClass.newInstance()
.
public <T> T getResultData(Class<T> resultClass, other_args) {
...
return resultClass.newInstance();
}