У меня есть общий класс с подклассами:
class Item<T>
{
//
}
class IntItem extends Item<Integer>
{
//
}
Мне нужен метод для получения экземпляра Item из его класса. Я пробовал такие методы, как:
<T extends Item<T>> T getItem(Class<T> itemClass)
{
return ...
}
<T> Item<T> getItem(Class<Item<T>> itemClass)
{
return ...
}
Но это не работает:
// Does not compile: "inference variable T has incompatible equality constraints Integer,IntItem"
IntItem ii = getItem(IntItem.class);
Каков правильный способ сделать это?
РЕДАКТИРОВАТЬ после кардинального ответа системы
Обратите внимание, что вопрос касается только сигнатур дженериков/методов.
Тот же вопрос, но с передачей экземпляра элемента в качестве параметра:
IntItem ii = getItem2(anIntItem);
static <T extends Item<E>,E> T getItem(Class<T> itemClass)
{
return ...
}
static <T extends Item<E>,E> T getItem2(T item)
{
// Does not compile: "error: incompatible types: Item cannot be converted to T"
return getItem(item.getClass();
}
Во-первых, вашему методу getItem
нужен отдельный общий параметр для установки в вашем параметре Item
(я собираюсь использовать E
). Во-вторых, просто используйте Class#newInstance:
public static <T extends Item<E>, E> T getItem(Class<T> itemType)
throws InstantiationException, IllegalAccessException {
return itemType.newInstance();
}
Вы также можете полностью опустить часть extends Item<?>
. Хотя это позволит методу создавать экземпляры других типов, он по-прежнему будет отлично работать для типов Item.
Если в будущем вы захотите добавить параметры в свои конструкторы элементов, вы можете использовать Class#getConstructor(Class<?>...) или Class#getConstructors(), чтобы найти конструктор, который вы хотите использовать, затем Constructor#newInstance(Object...) для создания вашего экземпляра. Вот два примера:
// This example does NOT work with null arguments
public static <T> T getItem(Class<T> itemType, Object... arguments)
throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Class<?>[] parameterTypes = Arrays.stream(arguments).map(Object::getClass).toArray(Class[]::new);
return getItem(itemType, parameterTypes, arguments);
}
// This example works with null arguments
public static <T> T getItem(Class<T> itemType, Class<?>[] parameterTypes, Object[] arguments)
throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Constructor<T> constructor = itemType.getConstructor(parameterTypes);
return constructor.newInstance(arguments);
}
Ваше "во-первых" решает мою проблему, вы получите ответ. Но я понимаю, что есть побочная проблема, я обновлю свой вопрос.