实例化类型参数的对象

时间:2008-11-18 20:20:06

标签: java generics reflection

我有一个模板类如下:

class MyClass<T>
{
    T field;
    public void myMethod()
    {
       field = new T(); // gives compiler error
    }
}

如何在班上创建T的新实例?

7 个答案:

答案 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();
        }