Родовая функция Java: как возвратить Универсальный тип

Вот является 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.

13
задан bmargulies 24 December 2009 в 17:23
поделиться

5 ответов

Это невозможно сделать в стандартном Java API. Тем не менее, существуют утилитные классы, которые могут получить Type из общего класса. Например, в Google Gson (который конвертирует JSON в полноценный Javabeans и наоборот) есть класс TypeToken . Вы можете использовать его следующим образом:

List<Person> persons = new Gson().fromJson(json, new TypeToken<List<Person>>() {}.getType());

Такая конструкция - это именно то, что вам нужно. Вы можете найти здесь исходный код, он также может оказаться полезным. Требуется только дополнительный метод getResultData(), который может принимать Type.

.
7
ответ дан 2 December 2019 в 00:31
поделиться

Ну, вот уродливый (частичный) раствор. Вы не можете параметризовать общий параметр, поэтому вы не можете записать

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-парама, если бы он существовал в сигнатуре класса.

.
2
ответ дан 2 December 2019 в 00:31
поделиться

Да, я не думаю, что это возможно.

Представь себе этот сценарий. У вас есть файл с сериализованным объектом, который вы хотите прочитать. Если вы сделаете функцию универсальной, вы сможете использовать ее без гипса. Но допустим, что у вас есть карта, сериализованная в файл.

Когда вы десериализуете ее, нет способа узнать , какой тип оригинальной универсальной карты был. Что касается java, это просто карта

Я столкнулся с этим со списками, и это было раздражающе. Но в итоге я создал общий класс "конвертирования коллекции", который принимает коллекцию и "конвертер" (который может быть анонимным внутренним типом).

Затем, когда вы выполняете итерацию по преобразующей коллекции, каждый элемент отбрасывается. И это решило проблему с предупреждением. Просто избавиться от предупреждения - большая работа, но я не думаю, что это было основной причиной, по которой я придумал этот фреймворк. Также можно сделать более мощные вещи, например, взять коллекцию имён файлов, а потом написать конвертер, который загрузит данные в файл, или сделает запрос, или ещё что-нибудь.

2
ответ дан 2 December 2019 в 00:31
поделиться

Итак, если я правильно понял, что вы на самом деле пытаетесь сделать (незаконный псевдосинтаксис):

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.* не помогут:

  1. Нет такого понятия как Class> и, следовательно, нет способа динамически создать его экземпляр.
  2. На самом деле нет способа объявить рассматриваемый метод как возвращающий T
1
ответ дан 2 December 2019 в 00:31
поделиться

Вы можете использовать TypeLiteral, если вы хотите использовать типизированные контейнерные классы. Они используются в Guice для обеспечения типовой безопасности. Дополнительные примеры см. в Guice Source code и в классе TypeLiteral.

Кстати, не нужно использовать кастинг, например, если вы вызываете resultClass.newInstance().

public <T> T getResultData(Class<T> resultClass, other_args) {       
   ...
   return resultClass.newInstance();
}
1
ответ дан 2 December 2019 в 00:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: