我有一个模板类如下:
class MyClass<T>
{
T field;
public void myMethod()
{
field = new T(); // gives compiler error
}
}
如何在班上创建T的新实例?
答案 0 :(得分:73)
在类型擦除之后,所有关于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();
}
}
答案 1 :(得分:13)
另一种非反思方法是使用混合构建器/抽象工厂模式。
在Effective Java中,Joshua Bloch详细介绍了Builder模式,并提出了一个通用的Builder接口:
public interface Builder<T> {
public T build();
}
具体构建器可以实现此接口,外部类可以使用具体构建器根据需要配置构建器。构建器可以作为Builder<T>
传递给MyClass。
使用此模式,即使T
具有构造函数参数或需要其他配置,您也可以获得T
的新实例。当然,您需要一些方法将Builder传递给MyClass。如果您无法将任何内容传递给MyClass,那么Builder和Abstract Factory就会出来。
答案 2 :(得分:11)
这可能比你正在寻找的更重量级,但它也会起作用。请注意,如果采用这种方法,在构造时将工厂注入MyClass更有意义,而不是在每次调用它时将它传递给方法。
interface MyFactory<T>
{
T newObject();
}
class MyClass<T>
{
T field;
public void myMethod(MyFactory<T> factory)
{
field = factory.newObject()
}
}
答案 3 :(得分:1)
如果您愿意继承子类,也可以避免删除,请查看 http://www.artima.com/weblogs/viewpost.jsp?thread=208860
答案 4 :(得分:0)
一种选择是将其与对象一起投射
{field = (T) new Object();}
field最初将是Object类型,但随后将强制转换为T类型。这很丑陋,因为将强制转换减小为零是对象初始化的目标。但是我认为这会起作用。
答案 5 :(得分:-1)
这里是使用浇铸的最佳和简便的解决方案。是的,这看起来很丑,但我在这里看到的更好。
if awk -F , 'BEGIN { OFS=FS; rc=0 } ++$NF >= 5 { rc=1 } 1; END { exit rc }' halted.txt >halted.txt.tmp
then
: nothing
else
echo "$0: we are done" >&2
fi
mv halted.txt.tmp halted.txt
答案 6 :(得分:-3)
Class classOfT
try {
t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
} catch (Exception e) {
e.printStackTrace();
}