ジェネリクスの基礎と応用 Twetter : @nagise はてな : Nagise 所属     (株) Abby      java-ja     北陸エンジニアグループ
ジェネリクスのスコープメソッドの中でのみ有効なジェネリクスpublic static <T> void hoge(T t) { … }インスタンスの中でのみ有効なジェネリク    スclass Hoge<T> {    Tt;    ...}
ジェネリックメソッド     メソッドの引数と戻          り値の型の関係を表     す           メソッドの複数の引     数の型の関係を表す
ジェネリックメソッドの例java.util.Collections クラスリスト内に出現する指定された値をすべてほかの値に置き換えます。public static <T> boolean replaceAll     (List<T> list...
ジェネリックメソッドの例java.util.Collections クラス指定されたオブジェクトだけを格納している不変のセットを返しますpublic static <T> Set<T> singleton(T o)引数が T 型で、戻り値が S...
ジェネリックメソッドの例java.util.Collections クラスデフォルトの乱数発生の元を使用して、指定されたリストの順序を無作為に入れ替えます。public static void shuffle(List<?> list)引数1つ...
ジェネリックメソッド     メソッドの引数と戻          り値の型の関係を表     す           メソッドの複数の引     数の型の関係を表す
ジェネリックメソッドの呼び出      し方List<String> list = new ArrayList<String>();list.add("hoge");Collections.<String>replaceAll(list, "h...
インスタンスの I/O       複数のメソッ              ド間の引数・戻       り値の型の関係       性               公開されてい       るフィールド               内部クラス
ジェネリックなインスタンスの       例java.util.ArrayList の例public boolean add(E e)public E get(int index)複数のメソッド間で型の関連性を表現している
文法のはなしpublic class Syntax<T>  implements Iterable<String> {  public <X> void hoge(X x) {   List<X> list = new ArrayList<X>...
3種類の<> 型変数の宣言class Hoge<T> {}public <T> void hoge() {} 型変数のバインドnew ArrayList<String>();class Hoge extends ArrayList<Stri...
サンプルのクラス
型のバインドジェネリックメソッドの例宣言側 仮型引数( type-parameter )public static <T> boolean replaceAll     (List<T> list, T oldVal, T newVal)利用側...
型のバインドジェネリッククラスの例宣言側 仮型引数( type-parameter )public class ArrayList<E> {...}利用側 実型引数( type-argument )List<String> list = new...
( 参考 ) 仮引数と実引数メソッドの仮引数と実引数との対比宣言側 仮引数( parameter )public void hoge(int index){...}利用側 実引数( argument )hoge(123);
型変数の境界  class Hoge<T extends B>型変数の宣言時には境界を指定できる    new Hoge<A>(); ←   NG    new Hoge<B>(); ←   OK   new Hoge<B2>(); ←    ...
型変数の境界class Hoge <T extends A & Serializable>      & で繋いでインタフェースを       境界に加えることができる
中級編
パラメータ化された型の代入互換       性B[] arrayB = new B[1];A[] arrayA = arrayB;arrayA[0] = new B2(); → ArrayStoreException が発生List<B> li...
異なる代入互換性B の集合型 ArrayList<B> はA の集合型 ArrayList<A> の    代理をできない
ワイルドカードの使用ArrayList<? extends B> の範囲ArrayList<? super B> の範囲
<? extends ~ > の入力制約List<? extends B> には add() できない    List<C> 型を代入    B 型を add() とする    List<C> に B 型が add() される ←矛盾 ...
<? super ~ > の出力制約ArrayList<? super B> にはB 型を add() できるただし get() は Object 型としてしか返せない
継承によるバインドpublic class StringList  extends ArrayList<String> {}というクラスを作るとStringList list = new StringList();list.add("hoge"...
複雑になる前にMap<String, Map<Integer, List<Hoge>>>みたいにジェネリクスが複雑化するようなら適度なレベルでした継承クラスを作ることでシンプルでわかりやすくなるクラスを作るのをサボらない
上級編
再帰ジェネリクスpublic abstract class  Hoge<T extends Hoge<T>> {    public abstract T getConcreteObject();}Hoge 型の型変数 T は Hoge 型を継...
再帰する型変数へのバインドnew でバインドできないHoge<?> hoge = new Hoge<Hoge<...>>();再帰ジェネリクスは継承で扱うpublic class Piyo extends Hoge<Piyo> {...}
再帰ジェネリクスの効能public class Piyo extends Hoge<Piyo> {  @Override  public Piyo getConcreteObject() {   return this;  }}このようにすると...
再帰ジェネリクスの効能public abstract class  Hoge<T extends Hoge<T>> {    public abstract T getConcreteObject();}親クラスで定義されたメソッドなのに子クラ...
再帰ジェネリクスの使用例java.lang.Enum クラスの例public abstract class Enum<E extends Enum<E>>        implements Comparable<E>, Serializabl...
再帰ジェネリクスの使用例enum SampleEnum {  ONE,  TWO,}に対してSampleEnum.ONE.compareTo(SampleEnum.TWO);は安全に compareTo できる。他の enum と比較しようとす...
内部クラスのジェネリクス内部クラスは外部クラスの型変数を利用できるpublic class Outer<T> {  public class Inner {   T genericField;  }}
内部クラスの new の仕方内部クラスの new の仕方知ってますか?Outer<String> outer = new Outer<String>();Outer<String>.Inner inner = outer.new Inner()...
内部クラスの利用例public class SampleList<T> extends ArrayList<T> {  @Override  public Iterator<T> iterator() {   return super.iter...
new T() したい「 Java のジェネリクスは new T() ってできないのがクソだよね」「お前の設計がクソなんじゃないの?」
コンストラクタ Java のオブジェクト指向 interface や親クラスとして 振る舞うことが要求される   具象型の特有の情報を押し込める場所はコンストラクタ
コンストラクタコンストラクタの引数の形は継承で     制約できませんやりたければ Factory クラス作れ
Factory の実装例interface HogeFactory<T extends A> {  /** デフォルトコンストラクタ的な */  T newInstance();}インスタンスの生成に必要なデータを Factory で制約pub...
妥協例public <T extends A> T template(T obj) {  try {   return (T)obj.getClass().newInstance();  } catch (InstantiationExcept...
C# の例class MyGenericClass<T> where T : new() {}T 型にデフォルトコンストラクタがあることという制約ダサいけど妥当な妥協点か
変態編
再帰での相互参照二つの型の具象型が、相互に相手の具象型を知っているclass Hoge<H extends Hoge<H, P>,   P extends Piyo<H, P>>class Piyo<H extends Hoge<H, P>, ...
相互再帰+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...
内部クラスでグルーピング二つのクラスを囲うクラスを作ってHoge と Piyo を内部クラスにすれば…!public abstract class Outer<H extends Outer<H, P>.Hoge, P extends Oute...
まとめ型変数でメソッドやインスタンスの I/O の 型の関連性を表す→ まずは綺麗なオブジェクト指向の設計を文法をマスターするには3種類の<>を意識するジェネリクスが複雑になりすぎないように継承でのバインドを利用する再帰ジェネリクスを応用すれば...
Upcoming SlideShare
Loading in …5
×

ジェネリクスの基礎と応用 JJUG CCC 2012 Fall

6,876 views

Published on

JJUG CCC 2012 Fall のセッション資料 #jjug_r12

Published in: Technology
  • Be the first to comment

ジェネリクスの基礎と応用 JJUG CCC 2012 Fall

  1. 1. ジェネリクスの基礎と応用 Twetter : @nagise はてな : Nagise 所属   (株) Abby    java-ja   北陸エンジニアグループ
  2. 2. ジェネリクスのスコープメソッドの中でのみ有効なジェネリクスpublic static <T> void hoge(T t) { … }インスタンスの中でのみ有効なジェネリク スclass Hoge<T> { Tt; ...}
  3. 3. ジェネリックメソッド メソッドの引数と戻  り値の型の関係を表 す  メソッドの複数の引 数の型の関係を表す
  4. 4. ジェネリックメソッドの例java.util.Collections クラスリスト内に出現する指定された値をすべてほかの値に置き換えます。public static <T> boolean replaceAll (List<T> list, T oldVal, T newVal)3つの引数が List<T> 型、 T 型、 T 型という関係性
  5. 5. ジェネリックメソッドの例java.util.Collections クラス指定されたオブジェクトだけを格納している不変のセットを返しますpublic static <T> Set<T> singleton(T o)引数が T 型で、戻り値が Set<T> 型という関係性
  6. 6. ジェネリックメソッドの例java.util.Collections クラスデフォルトの乱数発生の元を使用して、指定されたリストの順序を無作為に入れ替えます。public static void shuffle(List<?> list)引数1つだけなので関連性を示す必要がない
  7. 7. ジェネリックメソッド メソッドの引数と戻  り値の型の関係を表 す  メソッドの複数の引 数の型の関係を表す
  8. 8. ジェネリックメソッドの呼び出 し方List<String> list = new ArrayList<String>();list.add("hoge");Collections.<String>replaceAll(list, "hoge", "piyo");List<Integer> intList = new ArrayList<Integer>();intList.add(42);Collections.<Integer>replaceAll(intList, 42, 41);
  9. 9. インスタンスの I/O 複数のメソッ  ド間の引数・戻 り値の型の関係 性  公開されてい るフィールド  内部クラス
  10. 10. ジェネリックなインスタンスの 例java.util.ArrayList の例public boolean add(E e)public E get(int index)複数のメソッド間で型の関連性を表現している
  11. 11. 文法のはなしpublic class Syntax<T> implements Iterable<String> { public <X> void hoge(X x) { List<X> list = new ArrayList<X>(); list.add(x); } @Override public Iterator<String> iterator() { return null; }}似て非なる<>を色分けしてみました
  12. 12. 3種類の<> 型変数の宣言class Hoge<T> {}public <T> void hoge() {} 型変数のバインドnew ArrayList<String>();class Hoge extends ArrayList<String> {}Collections.<String>replaceAll( list, "hoge", "piyo"); パラメータ化された型( parameterized type )List<String> list;
  13. 13. サンプルのクラス
  14. 14. 型のバインドジェネリックメソッドの例宣言側 仮型引数( type-parameter )public static <T> boolean replaceAll (List<T> list, T oldVal, T newVal)利用側 実型引数( type-argument )Collections.<String>replaceAll( list, "hoge", "piyo");
  15. 15. 型のバインドジェネリッククラスの例宣言側 仮型引数( type-parameter )public class ArrayList<E> {...}利用側 実型引数( type-argument )List<String> list = new ArrayList<String>();
  16. 16. ( 参考 ) 仮引数と実引数メソッドの仮引数と実引数との対比宣言側 仮引数( parameter )public void hoge(int index){...}利用側 実引数( argument )hoge(123);
  17. 17. 型変数の境界 class Hoge<T extends B>型変数の宣言時には境界を指定できる new Hoge<A>(); ← NG new Hoge<B>(); ← OK new Hoge<B2>(); ← NG new Hoge<C>(); ← OK
  18. 18. 型変数の境界class Hoge <T extends A & Serializable> & で繋いでインタフェースを 境界に加えることができる
  19. 19. 中級編
  20. 20. パラメータ化された型の代入互換 性B[] arrayB = new B[1];A[] arrayA = arrayB;arrayA[0] = new B2(); → ArrayStoreException が発生List<B> listB = new ArrayList<B>();List<A> listA = listB;listA.add(new B2()); → コンパイルエラー
  21. 21. 異なる代入互換性B の集合型 ArrayList<B> はA の集合型 ArrayList<A> の 代理をできない
  22. 22. ワイルドカードの使用ArrayList<? extends B> の範囲ArrayList<? super B> の範囲
  23. 23. <? extends ~ > の入力制約List<? extends B> には add() できない List<C> 型を代入 B 型を add() とする List<C> に B 型が add() される ←矛盾 get() は B 型の戻り値を返す
  24. 24. <? super ~ > の出力制約ArrayList<? super B> にはB 型を add() できるただし get() は Object 型としてしか返せない
  25. 25. 継承によるバインドpublic class StringList extends ArrayList<String> {}というクラスを作るとStringList list = new StringList();list.add("hoge");String str = list.get(0);といったように、型変数のないクラスになる
  26. 26. 複雑になる前にMap<String, Map<Integer, List<Hoge>>>みたいにジェネリクスが複雑化するようなら適度なレベルでした継承クラスを作ることでシンプルでわかりやすくなるクラスを作るのをサボらない
  27. 27. 上級編
  28. 28. 再帰ジェネリクスpublic abstract class Hoge<T extends Hoge<T>> { public abstract T getConcreteObject();}Hoge 型の型変数 T は Hoge 型を継承していなくてはなら ない
  29. 29. 再帰する型変数へのバインドnew でバインドできないHoge<?> hoge = new Hoge<Hoge<...>>();再帰ジェネリクスは継承で扱うpublic class Piyo extends Hoge<Piyo> {...}
  30. 30. 再帰ジェネリクスの効能public class Piyo extends Hoge<Piyo> { @Override public Piyo getConcreteObject() { return this; }}このようにするとPiyo piyo = new Piyo();Piyo piyo2 = piyo.getConcreteObject();
  31. 31. 再帰ジェネリクスの効能public abstract class Hoge<T extends Hoge<T>> { public abstract T getConcreteObject();}親クラスで定義されたメソッドなのに子クラスの具象型を扱うことができる…!
  32. 32. 再帰ジェネリクスの使用例java.lang.Enum クラスの例public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { public final int compareTo(E o) {…}}
  33. 33. 再帰ジェネリクスの使用例enum SampleEnum { ONE, TWO,}に対してSampleEnum.ONE.compareTo(SampleEnum.TWO);は安全に compareTo できる。他の enum と比較しようとするとコンパイルエラー
  34. 34. 内部クラスのジェネリクス内部クラスは外部クラスの型変数を利用できるpublic class Outer<T> { public class Inner { T genericField; }}
  35. 35. 内部クラスの new の仕方内部クラスの new の仕方知ってますか?Outer<String> outer = new Outer<String>();Outer<String>.Inner inner = outer.new Inner();内部クラスは外部クラスのインスタンスに紐づく「インスタンスの I/O で型の関連性を示す」の I/O には内部クラスも含まれます
  36. 36. 内部クラスの利用例public class SampleList<T> extends ArrayList<T> { @Override public Iterator<T> iterator() { return super.iterator(); } public class SampleIterator implements Iterator<T> { // 略 }}そもそも内部クラスの使いどころが難しいですが。
  37. 37. new T() したい「 Java のジェネリクスは new T() ってできないのがクソだよね」「お前の設計がクソなんじゃないの?」
  38. 38. コンストラクタ Java のオブジェクト指向 interface や親クラスとして 振る舞うことが要求される 具象型の特有の情報を押し込める場所はコンストラクタ
  39. 39. コンストラクタコンストラクタの引数の形は継承で 制約できませんやりたければ Factory クラス作れ
  40. 40. Factory の実装例interface HogeFactory<T extends A> { /** デフォルトコンストラクタ的な */ T newInstance();}インスタンスの生成に必要なデータを Factory で制約public class HogeTemplate { public <T> T template(HogeFactory<T> factory) { return factory.newInstance(); }}こうすればインスタンスの生成は可能になる、が面倒
  41. 41. 妥協例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); }}
  42. 42. C# の例class MyGenericClass<T> where T : new() {}T 型にデフォルトコンストラクタがあることという制約ダサいけど妥当な妥協点か
  43. 43. 変態編
  44. 44. 再帰での相互参照二つの型の具象型が、相互に相手の具象型を知っている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>
  45. 45. 相互再帰+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>>やりすぎです
  46. 46. 内部クラスでグルーピング二つのクラスを囲うクラスを作って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(); }}やりすぎです
  47. 47. まとめ型変数でメソッドやインスタンスの I/O の 型の関連性を表す→ まずは綺麗なオブジェクト指向の設計を文法をマスターするには3種類の<>を意識するジェネリクスが複雑になりすぎないように継承でのバインドを利用する再帰ジェネリクスを応用すればサブクラスで具象型を扱える

×