【Java】ジェネリクスの型パラメータTでインスタンス化してみる


型パラメータのインスタンス化に関して

Javaでジェネリクスを使ったクラスやメソッドを、定義する時があると思います。定義の概要についてはJava ジェネリクス(クラス、メソッドを定義する)の記事をご参照頂ければと思います。
さて、このジェネリクスでの型パラメータの制約ですが、上記の記事にもある通り「new T()できない」や「new T[]できない」といった制約があります。つまり以下のようなコードはコンパイルでエラーとなります。

class TypeParamTest<T> {
    public T tObject;
    TypeParamTest() {
        this.tObject = new T(); // コンパイルエラー
    }
}

Javaのジェネリクスで,T.class や new T() ができず悩んだ話 (型パラメータのインスタンス化に関し、フレームワーク設計からケーススタディ)の記事にある通り、そもそもこういうケースは設計がイケてないという話なのですが、どうしてもやりたいというケースもあると思うので対応方法を少し調べてみました。

対応方法

Instantiating object of type parameterの記事に、いくつか対応方法が紹介されています。個人的には、Supplierで該当の型のコンストラクタを受け取って、それでインスタンス化するという方法が分かりやすくて良いかなと思いました。

実装サンプル

Supplierでコンストラクタを受け取る実装のサンプルです。

package sample;

import java.util.function.Supplier;

class TypeParamTest<T> {
    public T tObject;
    TypeParamTest(Supplier<? extends T> ctor) {
        this.tObject =  ctor.get();
    }
}

public class TypeParamSample {
    public static void main(String[] args) {
        TypeParamTest<String> test = new TypeParamTest(String::new);
    }
}