У меня есть следующий шаблонный класс:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
Как мне создать новый экземпляр T в моем классе?
Ответы:
После стирания типа все, что известно, T
это то, что это какой-то подкласс Object
. Вам нужно указать фабрику для создания экземпляров T
.
Один из подходов может использовать Supplier<T>
:
class MyClass<T> {
private final Supplier<? extends T> ctor;
private T field;
MyClass(Supplier<? extends T> ctor) {
this.ctor = Objects.requireNonNull(ctor);
}
public void myMethod() {
field = ctor.get();
}
}
Использование может выглядеть так:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
В качестве альтернативы вы можете предоставить Class<T>
объект, а затем использовать отражение.
class MyClass<T> {
private final Constructor<? extends T> ctor;
private T field;
MyClass(Class<? extends T> impl) throws NoSuchMethodException {
this.ctor = impl.getConstructor();
}
public void myMethod() throws Exception {
field = ctor.newInstance();
}
}
java.util.function.Supplier
Другой неотражающий подход - использование гибридного паттерна Builder / Abstract Factory.
В «Эффективной Java» Джошуа Блох подробно рассматривает шаблон Builder и отстаивает общий интерфейс Builder:
public interface Builder<T> {
public T build();
}
Конкретные строители могут реализовать этот интерфейс, а внешние классы могут использовать конкретный конструктор для настройки Построителя по мере необходимости. Строитель может быть передан MyClass как Builder<T>
.
Используя этот шаблон, вы можете получить новые экземпляры T
, даже если они T
имеют параметры конструктора или требуют дополнительной настройки. Конечно, вам понадобится способ передать Builder в MyClass. Если вы не можете передать что-либо в MyClass, значит, Builder и Abstract Factory исключены.
Это может быть тяжелее, чем то, что вы ищете, но это тоже сработает. Обратите внимание: если вы воспользуетесь этим подходом, было бы разумнее внедрить фабрику в MyClass, когда она создана, вместо того, чтобы передавать ее в свой метод при каждом ее вызове.
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
Если вы хотите создать подкласс, вы также можете избежать стирания, посетите http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Класс classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}
Supplier
он находится? `MyClass (Class <? Extends T> impl)` должен объявлять `throws NoSuchMethodException` для компиляции. К сожалению, ваш ответ не подходит новичку в Java.