25. 継承によるバインド
public class StringList
extends ArrayList<String> {}
というクラスを作ると
StringList list = new StringList();
list.add("hoge");
String str = list.get(0);
といったように、型変数のないクラスになる
54. Factory の実装例
interface HogeFactory<T extends A> {
/** デフォルトコンストラクタ的な */
T newInstance();
}
インスタンスの生成に必要なデータを Factory で制約
public class HogeTemplate {
public <T> T template(HogeFactory<T> factory)
{
return factory.newInstance();
}
}
こうすればインスタンスの生成は可能になる、が面倒
55. 妥協例
public <T extends A> T template(T obj) {
try {
return (T)obj.getClass().newInstance();
} catch (InstantiationException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public <T extends A> T template(Class<T> clazz) {
try {
return (T)clazz.newInstance();
} catch (InstantiationException |
IllegalAccessException e) {
throw new RuntimeException(e);
}
}
デフォルトコンストラクタがあることが前提
56. C# の例
class MyGenericClass<T> where T : new() {}
T 型にデフォルトコンストラクタがあることという制約。
デフォルトコンストラクタがあることを保証させることで
インスタンス生成を可能とする。
この制約はダサい制約ではあるが妥当な妥協点か。
Java でもリフレクションで生成する場合に
デフォルトコンストラクタがあることという制限をつけがち。
57. 継承によるバインドの場合
Class # getGenericSuperclass() という福音
継承によるバインドであれば、型情報から型変数に何がバ
インドされたかを知ることができる
Type を ParameterizedType にキャスト
getActualTypeArguments() でバインドされた実体
実体の Type を Class にキャストして newInstance()
ただし、デフォルトコンストラクタがあるものとする
http://d.hatena.ne.jp/Nagise/20130815
61. 再帰での相互参照
二つの型の具象型が、相互に相手の具象型を知っている
class Hoge<H extends Hoge<H, P>,
P extends Piyo<H, P>>
class Piyo<H extends Hoge<H, P>,
P extends Piyo<H, P>>
実装は
class HogeImpl extends Hoge<HogeImpl, PiyoImpl>
class PiyoImpl extends Piyo<HogeImpl, PiyoImpl>
62. 相互再帰+1
汎用型変数 T を追加してみる
class Hoge<T, H extends Hoge<T, H, P>,
P extends Piyo<T, H, P>>
class Piyo<T, H extends Hoge<T, H, P>,
P extends Piyo<T, H, P>>
実装クラス
class HogeImpl<T> extends
Hoge<T, HogeImpl<T>, PiyoImpl<T>>
class PiyoImpl<T> extends
Piyo<T, HogeImpl<T>, PiyoImpl<T>>
やりすぎです
63. 内部クラスでグルーピング
二つのクラスを囲うクラスを作って
Hoge と Piyo を内部クラスにすれば…!
public abstract class Outer
<H extends Outer<H, P>.Hoge,
P extends Outer<H, P>.Piyo> {
public abstract class Hoge {
public abstract P getConcretePiyo();
}
public abstract class Piyo {
public abstract H getConcreteHoge();
}
}
やりすぎです
65. 応用例
型変数の部分適用
http://d.hatena.ne.jp/Nagise/20110124/1295874192
Java による高階型変数の実装
public class Hoge extends KeyGroup<Hoge> {
private static final Hoge singleton = new Hoge();
public static final Hoge.Key<String>
HOGE_STRING = singleton.new Key<String>();
}
public class KeyValue<KG extends KeyGroup<KG>> {
public <T> void put(KeyGroup<KG>.Key<T> key, T value){}
}
KeyValue<Hoge> tm = new KeyValue<Hoge>();
tm.put(Hoge.HOGE_STRING, "hoge");