У меня есть следующий шаблонный класс:
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();
}
}
@ user927387 java.util.function.Supplier
Поставщик <T> требует Java 8, JFTR везде, где стоит.
Если вы хотите создать подкласс, вы также можете избежать стирания, проверьте http://www.artima.com/weblogs/viewpost.jsp?thread=208860
Это может быть тяжелее того, что вы ищете, но это тоже сработает. Обратите внимание: если вы воспользуетесь этим подходом, было бы разумнее внедрить фабрику в MyClass, когда она создана, вместо того, чтобы передавать ее в свой метод при каждом ее вызове.
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
Хороший, неотразимый подход; отражение - не всегда вариант. myMethod должен иметь возможность принимать MyFactory <? расширяет T>, верно?
Хороший прием - вы захотите поместить в фабрику ограниченный подстановочный знак, чтобы разрешить создание объектов типа T и подклассов T в myMethod ().
Другой неотражающий подход - использовать гибридный паттерн Строитель / Абстрактная фабрика.
В Effective Java Джошуа Блох подробно рассматривает шаблон Builder и защищает общий интерфейс Builder:
public interface Builder<T> {
public T build();
}
Конкретные строители могут реализовать этот интерфейс, а внешние классы могут использовать конкретный конструктор для настройки Построителя по мере необходимости. Конструктор можно передать MyClass как Builder<T>.
Используя этот шаблон, вы можете получить новые экземпляры T, даже если T имеет параметры конструктора или требует дополнительной настройки. Конечно, вам понадобится способ передать Builder в MyClass. Если вы не можете передать что-либо в MyClass, значит, Builder и Abstract Factory исключены.
Класс classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}
Где объявлен этот класс classOfT?
Один из вариантов - использовать его с помощью Object
{field = (T) new Object();}
Первоначально поле будет иметь тип Object, но затем оно будет преобразовано к типу T. Это уродливо, потому что уменьшение преобразования до нуля - это то, что должно быть целью инициализации объекта. Но я думаю, что это сработает.
В каком пакете находится
Supplier? `MyClass (Class <? Extends T> impl)` должен объявлять `throws NoSuchMethodException` для компиляции. К сожалению, ваш ответ не подходит для новичков в Java.