ジェネリックコンストラクタの使いどころ
メソッドと同じく、コントストラクタをジェネリックにする(型パラメータをとる)ことができる。
ところがコンストラクタの型パラメータの使い途がよく分からない。
参考:
コンストラクタジェネリック - カタヤマンがプログラマチックに今日もコードアシスト
Enumのコンストラクタのローカルなジェネリクス型パラメータの怪
そこで使い途を考えた。
package test; public class GenericConstructorTest { // インスタンスで必要なのはRunnable private Runnable runnable; // コンストラクタ 上限境界にCloneable public <T extends Runnable & Cloneable> GenericConstructorTest( final T runnable) { try { // リフレクションでclone() this.runnable = (Runnable) runnable.getClass().getMethod("clone") .invoke(runnable); } catch (Exception e) { throw new IllegalArgumentException("need public clone()", e); } } public void start() { new Thread(this.runnable).start(); } // Runnable かつ Cloneable static class CloneableRunnable implements Runnable, Cloneable { @Override public void run() { System.out.println("hoge"); } @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError("unexpected exception", e); } } } // Runnableのみ static class OnlyRunnable implements Runnable { @Override public void run() { System.out.println("fuga"); } } public static void main(final String[] args) { new <CloneableRunnable> GenericConstructorTest(new CloneableRunnable()) .start(); // コンパイルエラー // new <OnlyRunnable> GenericConstructorTest(new OnlyRunnable()).start(); } }
コンストラクタに渡される引数runnableは、インスタンスが生成された後はRunnableでありさえすればいいが、
コンストラクタ内(インスタンスの初期化時)ではさらにCloneableでもあってほしい。
このような場合に、
これでrunnableがCloneableであることがコンパイル時にチェックできる。
この場合リフレクションでclone()を読んでいるので、あまりインターフェースのありがたみがないが…
まとめ
初期化時にしか必要ない上限境界インターフェースを(複数)指定するのに使える。
関連?
- 上限境界のインターフェースを型パラメータで複数にする話 http://d.hatena.ne.jp/t_yano/20101213/1292212666
- clone()がprotectedなのでインターフェースで呼べなくていまいちという話 Cloneable - ぐるぐる~
(2013/01/14追記)コンストラクタはメソッドの一種と考えれば、メソッドをジェネリックにする理由と同じと考えられる。
メソッドをジェネリックにする動機についてはあなたの知らない、メソッドに型変数を加えるべき理由〜引数を再帰的型に制限〜などで議論する。