我有一个模板类,如下所示:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
如何在课堂上创建T的新实例?
Answers:
在类型擦除之后,只知道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模式。
在Effective Java中,Joshua Bloch详细介绍了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初学者不友好。