å帰çã¸ã§ããªã¯ã¹ã®ä»£å ¥äºææ§
Javaã®ãããããã¸ã§ããªã¯ã¹ã®è©±ããããã*1
å帰çã¸ã§ããªã¯ã¹
ã¯ã©ã¹Hogeããã£ãã¨ãã¦ãåå¤æ°Tãåãã
public class Hoge<T> {}
ãã®Hogeã®åå¤æ°Tãextends Hogeã¨ããã¨
public class Hoge<T extends Hoge> {}
ããã¨ãT extends Hoge ã® Hoge ã rawåã ã¨è¦åããããHogeã®<>ã®é¨åã«Hogeåãç¶æ¿ããåãæå®ããªããã°ãªããªããããã§åå¤æ°T ã extends Hogeã ã£ãã®ã§ãä¸åº¦ããããTåããããããã
public class Hoge<T extends Hoge<T>> {}
ããã¯å帰çã¸ã§ããªã¯ã¹(recursive generics)ã¨å¼ã°ãã¦ããããã ã
追è¨ï¼åã¯åæã«èªå·±è¨ååã¸ã§ããªã¯ã¹ãªã©ã¨å¼ãã§ãããæ å ±ãµã³ã¯ã¹ï¼ä½µãã¦ã¿ã¤ãã«ãªã©ã表ç¾ããå帰çã¸ã§ããªã¯ã¹ãã«çµ±ä¸ãã¾ããã
å帰çã¸ã§ããªã¯ã¹ã®å©ç¨æ¹æ³
ãã¦ããã®ããã«ãã¦å®£è¨ãããHogeåã ããã©ããã£ã¦ä½¿ãã®ã ããããã¡ãã£ã¨Hogeåã®å¤æ°hogeã宣è¨ãã¦ã¿ãããããªããã
Hoge hoge = null;
å½ç¶ãªããHogeã®åå¤æ°ãæå®ããªãrawåãªã®ã§ã³ã³ãã¤ã«è¦åãã§ããåå¤æ°Tãæå®ããã°ãããã ãããTã¯Hogeãextendsãã¦ãããã ããHogeãå ¥ãã¦ã¿ãã
Hoge<Hoge> hoge = null;
ããã¨ã以ä¸ã®ãããªã¨ã©ã¼ãåºã(Eclipse3.6使ç¨)
Bound mismatch: The type Hoge is not a valid substitute for the bounded parameter <T extends Hoge<T>> of the type Hoge<T>
ãããããªãã®ã§
Hoge<?> hoge = null;
使ããªããããããã®ã¯ã©ã¹Hogeã®newãèãã¦ã¿ããã
new Hoge();
ããã¯rawåãªã®ã§è¦åãããã
new Hoge<?>();
ããã¯ã³ã³ãã¤ã«ã¨ã©ã¼ããã£ã±ã使ããªããããªãã*2ã
â¦ã¨æãã®ã¯æ©è¨ã ãããã¤ã¯extends ãã¦ä½¿ã£ã¦åãã¦ç価ãçºæ®ããã
public class Piyo extends Hoge<Piyo> {}
ããã§Hogeåã«ã¡ã½ããã足ãã¦ã¿ããã
public class Hoge<T extends Hoge<T>> { public void hoge(T hoge) {} }
ããã¦Piyoã§ãã®ã¡ã½ããããªã¼ãã¼ã©ã¤ããã¦ã¿ãããEclipseãªãPiyoåã§hogeã¨ã¿ã¤ããã¦Ctrl+spaceã ã
public class Piyo extends Hoge<Piyo> { @Override public void hoge(Piyo hoge) { // TODO Auto-generated method stub super.hoge(hoge); } }
注ç®ããã®ã¯hogeã¡ã½ããã®å¼æ°ã®åã ãå ·è±¡åã®Piyoåã«ãªã£ã¦ãããã¹ã¼ãã¼ã¯ã©ã¹ã®Hogeåã¯å½ç¶ãªããPiyoã¯ã©ã¹ãªãã¦ãã®ã¯ç¥ããªãããã ãããã®Piyoã¯ã©ã¹ã§ãªã¼ãã¼ã©ã¤ããããã¡ã½ããã®å¼æ°ã¯Piyoåã¨ããå ·è±¡åã«ãããã¨ãã§ããããã ã
ãããå©ç¨ãã¦
public class Hoge<T extends Hoge<T>> { public void hoge(T hoge) {} public void loop(List<T> list) { for (T hoge : list) { hoge.hoge(hoge); } } }
ã®ããã«ã«ã¼ããæ¸ããã¨ãã§ãããåç´ãªã«ã¼ãã«éãããè¤éãªå¦çãæ¸ãäºãã§ãããã¤ã¾ãTemplate Method ãã¿ã¼ã³ãæ½è±¡åãããã¨ãã§ããã*3
ããã«ç¶æ¿ãã
ã¨ããã§ããã®Piyoåãç¶æ¿ããå ´åã«ã¡ãã£ã¨å°ãã
public class Fuga extends Piyo { @Override public void hoge(Piyo hoge) {} }
PiyoåãHoge<Piyo>åãç¶æ¿ãã¦ããããã ãããHogeåã®åå¤æ°Tã¯Piyoåã§åºå®ã«ãªã£ã¦ãããã ãããPiyoãç¶æ¿ããFugaã§ãHogeåã®åå¤æ°Tããã£ãã¨ããã¯Piyoåãªã®ã ãFugaåã«ã¯ãªããªãã
ãããåé¿ããããã«æ°ããªåå¤æ°ãå°å ¥ããPiyo2åãä½ã£ã¦ã¿ããã
public class Piyo2<P extends Piyo2<P>> extends Hoge<P> { public void hoge(P hoge) { hoge.piyo(); } public void piyo2() {} }
Hogeåã®Tã¯extends Hogeã ã£ãããããã§ã¯extends Piyo2ã§ããåå¤æ°P ãä½ã£ããPã¯Piyo2ãç¶æ¿ãã¦ããããã ãããPåã®å¤æ°ã«å¯¾ãã¦piyo2()ãå¼åºããã¨ãã§ãã¦ããããã®Piyo2åãç¶æ¿ãã¦Fuga2åãä½ã£ã¦ã¿ãã
public class Fuga2 extends Piyo2<Fuga2> { @Override public void hoge(Fuga2 hoge) {} }
ã¨ãªã£ã¦ãhoge()ã®å¼æ°ãå ·è±¡åFuga2ã«ãªã£ãã
ä»£å ¥ã®åé¡
ãã¦ãããã§
Hoge
â Piyo - Fuga
â Piyo2 - Fuga2
ã¨ããç¶æ¿é¢ä¿ãã§ããã
Hogeã®åå¤æ°Tã¯
- Piyo : Piyo
- Fuga : Piyo
- Piyo2 : P(extends Piyo2)
- Fuga2 : Fuga2
ã¨ãªã£ã¦ããããããªHogeãã¡ããªã¼ãåå¤æ°ã¨ãã¦ä½¿ãããã¯ã©ã¹Fooãç»å ´ããã¨ãããã
public class Foo<X extends Hoge<X>> {}
ãã®Fooåã®å¤æ°ã宣è¨ãã¦ã¿ãããããªããã
Foo<Piyo> piyo; // OK Foo<Fuga> fuga; // NG Foo<Piyo2> piyo2; // NG Foo<Fuga2> fuga2; // OK
ããã§FugaãPiyo2ã¯ã³ã³ãã¤ã«ã¨ã©ã¼ã¨ãªãããªãã ãããã
Fooã®åå¤æ°Xã¯ãextends Hoge
- Piyo : Piyo
- Fuga : Piyo
- Piyo2 : P(extends Piyo2)
- Fuga2 : Fuga2
ã¤ã¾ããFoo<X extends Hoge<X>>ã¨ããå¢çã®å ´åãXã®é¨åã¯åãã§ãªãã¦ã¯ãªãããFuga extends Hoge<Piyo>ã®ãããªã¯ã©ã¹ã¯åãä¸è´ããªãã®ã ã
å¢çããããã
Piyoåãç¶æ¿ããFugaåã使ããªãã£ã¦ã®ã¯é½åãæªããããã§Fooããå¢çãããããFoo2ãä½ã£ã¦ã¿ããã
public class Foo2<X extends Hoge<?>> {}
Foo<Piyo> piyo; // OK Foo<Fuga> fuga; // OK Foo<Piyo2> piyo2; // OK Foo<Fuga2> fuga2; // OK
ããã©ã¯ã©ããã³ã³ãã¤ã«ãããã¨ãã§ããã
ã¨ããã§ãHogeãç¶æ¿ãããããªã¯ã©ã¹ãä½ããã¨ãã§ããã
public class EvilPiyo extends Hoge<Piyo>{ @Override public void hoge(Piyo hoge) {} }
EvilPiyoã§ã¯Hogeåã®åå¤æ°Tã«å¯¾ãã¦EvilPiyoãæå®ããã®ã§ã¯ãªããHogeãç¶æ¿ããå¥ã®åPiyoãæå®ãã¦ããã
ãã®ãã¨ã示ãã¦ããã®ã¯ãHoge<T extends Hoge<T>>ã¨ããåå¤æ°ã®å®£è¨ã¯ãã¹ã¼ãã¼ã¯ã©ã¹å´ããæ示ãã¦ãµãã¯ã©ã¹ã«ãµãã¯ã©ã¹èªèº«ã®åãæ±ããããã¨ãã§ããããå®ç§ã«çµ±å¶ãããã¨ãåºæ¥ãããã§ã¯ãªãã¨ãããã¨ã ã
ãã®EvilPiyoã¯ã¾ãã«ãã®ç©´ãçªããåå¨ãªã®ã ãè¦åãç·©ããFoo2ã¯ãã®EvilPiyoãåã·ã¹ãã ã§æé¤ã§ããªãã
Foo<EvilPiyo> epiyo; // ã³ã³ãã¤ã«OK
å¢çãå³å¯ã«ãã
EvilPiyoã¯æé¤ãããããFugaã¯è¨±å®¹ããããFoo<X extends Hoge<X>>ã§ã¯Hogeã®åå¤æ°Tã«æ¸¡ãåã¨Xã®åãä¸è´ãã¦ãªãã¦ã¯ãªããªãã£ããFugaã¯extends Piyoã ã親åé¢ä¿ã§ãã£ã¦åä¸ã®åã§ã¯ãªããããã§ã
public class Foo3<X extends Hoge<? super X>> {}
ã¨ãã¦ã¿ãããXãFugaã®å ´åãHogeã®åå¤æ°Tã? super Xãã¤ã¾ã? super Fugaã§ããã°ããããã ãããHoge
Foo<Piyo> piyo; // OK Foo<Fuga> fuga; // OK Foo<Piyo2> piyo2; // NG Foo<Fuga2> fuga2; // OK Foo<EvilPiyo> epiyo; // NG
æ®å¿µãªã®ã¯Piyo2ãNGã«ãªã£ã¦ãã¾ããã¨ãããããããã¯Foo<Piyo2>ã®Piyo2ãrawåãªã®ãã¾ãããPiyo2<P extends Piyo2<P>> extends Hoge<P>ã§ãããããFoo<Piyo2<Piyo2<Piyo2<...>>>>ã¨ããã®ã表ç¾ã§ããªãã
åå¤æ°ã®ä¸æº
ãããªããã§ãå¤æ°å®£è¨ã§ã®Foo<Piyo2<Piyo2<Piyo2<...>>>>ã®æ¥µéã¿ãããªã®ãä»ã®Javaã®ã¸ã§ããªã¯ã¹ã§ã¯è¡¨ç¾ã§ããªããä¸æ¦ç¶æ¿ããåãä½ãå¿ è¦ãããã
ããã¦ãHoge<T extends Hoge<T>>ã®ãããªææ³ã¯ããµãã¯ã©ã¹èªèº«ã®åãæ±ãããã¨ããç®çãå¶ããããã®ãã¯ããã¯ã§ã¯ããããEvilPiyoã®ä¾ã®ãããªåã·ã¹ãã çãªæãããããã¨ãææããã
ã¤ã¾ãã¨ãããHoge<T extends Hoge<T>>ã®ãããªææ³ããç°¡æãªãã¼ã¯ã¼ãã§å®¹æã«å®£è¨ã§ããã°ããã®ã ã¨æããããã¯åãªãHoge<T extends Hoge<T>>ã®ã·ã³ã¿ãã¯ã¹ã·ã¥ã¬ã¼ã§ã¯ãªããEvilPiyoã®ãããªãã®ãæé¤ããå®å¿åºæ¥ãåå¤æ°ã§ããå¿ è¦ãããã
*1:æ¬ç¨¿ã¯再帰型のジェネリクス型変数の境界ã®ç¼ç´ã解説ç
*2:ã¡ãªã¿ã«class Piyo extends Hoge<Piyo>ãä½ãã¨ãnew Hoge<Piyo>();ã¨ãããã¨ãã§ããããã«ãªã
*3:ããã¯ãã¬ã¼ã ã¯ã¼ã¯ã®è¨è¨ãªã©ã§ã¯å½¹ç«ã¤ææ³ã ããæ½è±¡åãããã®ãããã«æ½è±¡åããã¨ãã話é¡ãªã®ã§ãç¸å½ãªã¹ã±ã¼ã«ããªãã¨å½¹ç«ããªããã¨ãå¤ã