Верните экземпляр класса с его общим типом
Вот простой пример, демонстрирующий проблему, связанную со стиранием, с которой я сталкиваюсь. У меня есть класс вроде этого:
public abstract class AbstractHandler<T> {
...
public abstract Class<T> handledType();
}
Тогда у меня есть эта реализация:
public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {
@Override
public Class<Map<String, List<Thing>>> handledType() {
//what do I return here?!
}
}
Я не могу вернуть Map<String, List<Thing>>.class
, так как это даже не действует синтаксически. Я попытался сделать общий тип параметра в подтипе HashMap<String, List<Thing>>
, а затем возвратить new HashMap<String, List<Thing>>().getClass()
, но это не работает, потому что тип возврата Class<T>#getClass()
равен Class<? extends T>
. Я посмотрел на TypeToken
из Guava, а метод getRawType
выглядел многообещающим, но он возвращает Class<? super T>
.
У меня есть обходное решение, которое выглядит так:
public class ThingListMap {
private Map<String, List<Thing>> thingListMap;
...
}
и я просто использую ThingListMap
как общий тип-параметр.
Другим возможным обходным путем является выполнение принудительного ввода:
public Class<Map<String, List<Thing>>> handledType() {
return (Class<Map<String, List<Thing>>>) new HashMap<String, List<Thing>>().getClass();
}
Есть ли более элегантный способ сделать это?
EDIT: В ответ на один из ответов я не могу изменить подпись метода handledType
, так как я не владею или не управляю его источником.
Ответы
Ответ 1
По какой-то причине Java не позволяет использовать Map.class
непосредственно для Class<Map<String, List<Thing>>>
. В любом случае, это непроверенный бросок.
Но легально перевести его дважды, сначала на Class<?>
, затем на Class<Map<String, List<Thing>>>
.
return (Class<Map<String, List<Thing>>>) (Class<?>) Map.class;
Будучи непроверенным, вы можете добавить @SuppressWarnings("unchecked")
.
Ответ 2
Гува подход к этому заключается в использовании TypeToken
. Ваш класс станет
public abstract class AbstractHandler<T> {
public TypeToken<T> handledType();
}
public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {
@Override
public TypeToken<Map<String, List<Thing>>> handledType() {
return new TypeToken<Map<String, List<Thing>>>() {};
}
}