实例化类型参数的对象

Mer*_*ous 79 java generics reflection

我有一个模板类如下:

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

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

eri*_*son 76

在类型擦除之后,所有已知的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();
  }

}
Run Code Online (Sandbox Code Playgroud)

用法可能如下所示:

MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
Run Code Online (Sandbox Code Playgroud)

或者,您可以提供一个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();
  }

}
Run Code Online (Sandbox Code Playgroud)

  • 只要有价值,Supplier&lt;T&gt; 就需要 Java 8、JFTR。 (2认同)

小智 14

另一种非反射方法是使用混合构建器/抽象工厂模式.

在Effective Java中,Joshua Bloch详细介绍了Builder模式,并提出了一个通用的Builder接口:

public interface Builder<T> {
  public T build();
}
Run Code Online (Sandbox Code Playgroud)

具体构建器可以实现此接口,外部类可以使用具体构建器根据需要配置构建器.构建器可以作为一个传递给MyClass Builder<T>.

使用此模式,您可以获得新的实例T,即使T具有构造函数参数或需要其他配置.当然,您需要一些方法将Builder传递给MyClass.如果你不能将任何东西传递给MyClass,那么Builder和Abstract Factory就会出来.


小智 12

这可能比你正在寻找的更重量级,但它也会起作用.请注意,如果采用这种方法,在构造时将工厂注入MyClass更有意义,而不是在每次调用时将其传递给方法.

interface MyFactory<T> 
{
    T newObject();
}

class MyClass<T> 
{
    T field;
    public void myMethod(MyFactory<T> factory)
    {
       field = factory.newObject()
    }
}
Run Code Online (Sandbox Code Playgroud)