web-dev-qa-db-ja.com

型パラメーターのオブジェクトのインスタンス化

次のようなテンプレートクラスがあります。

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

クラスにTの新しいインスタンスを作成するにはどうすればよいですか?

77
Mercurious

型の消去後、Tについて知られていることは、それがObjectのサブクラスであることだけです。 Tのインスタンスを作成するには、何らかのファクトリーを指定する必要があります。

1つのアプローチでは、 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();
  }

}
75
erickson

別の非反射アプローチは、ハイブリッドビルダー/抽象ファクトリーパターンを使用することです。

効果的なJavaでは、Joshua BlochはBuilderパターンを詳細に検討し、一般的なBuilderインターフェースを提唱しています。

public interface Builder<T> {
  public T build();
}

具象ビルダーはこのインターフェイスを実装でき、外部クラスは具象ビルダーを使用して必要に応じてビルダーを構成できます。ビルダーは、Builder<T>としてMyClassに渡すことができます。

このパターンを使用すると、Tにコンストラクターパラメーターがあるか、追加の構成が必要な場合でも、Tの新しいインスタンスを取得できます。もちろん、BuilderをMyClassに渡す何らかの方法が必要です。 MyClassに何も渡せない場合は、BuilderとAbstract Factoryが出ています。

13
InverseFalcon

これは、探しているものよりも重いかもしれませんが、機能します。このアプローチをとる場合、メソッドが呼び出されるたびにメソッドに渡すのではなく、構築時にMyClassにファクトリを注入する方が意味があることに注意してください。

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

class MyClass<T> 
{
    T field;
    public void myMethod(MyFactory<T> factory)
    {
       field = factory.newObject()
    }
}
11
Dan Hodge

サブクラスを使用する場合は、消去を回避することもできます http://www.artima.com/weblogs/viewpost.jsp?thread=20886

1
krosenvold