凪瀬 Blog
Programming SHOT BAR

目次

Blog 利用状況
  • 投稿数 - 260
  • 記事 - 0
  • コメント - 47085
  • トラックバック - 192
ニュース
広告
  • Java開発者募集中
  • 経歴不問
  • 腕に自信のある方
  • 富山市内
  • (株)凪瀬アーキテクツ
アクセサリ
  • あわせて読みたい
凪瀬悠輝(なぎせ ゆうき)
  • Java技術者
  • お茶好き。カクテル好き。
  • 所属は(株)凪瀬アーキテクツ
  • Twitter:@nagise

書庫

日記カテゴリ

 

2008年8月18日

Javaのジェネリクスはかなり強力で、相当の型を表現できるのですが、 代償として非常に複雑なものとなっています。

ややこしいのは、オブジェクト指向の部分の型の代入互換性と、 ジェネリクス型パラメータの部分の代入互換性は、表現こそ似ているものの、 その意味するところはまるで違うと言うことにあります。

端的には、C extends B, B extends Aの関係があるとして、 型B にはサブクラスであるCをキャストなしに安全に代入することができます。

B b = new C();

しかし、ジェネリクス型パラメータの場合の

List<B> listB = new ArrayList<C>();

はコンパイルエラーとなります。

List<? extends B> listBEx = new ArrayList<C>();

であれば代入が可能です。 このように、同じ継承階層の型を扱うのにもかかわらず、その代入互換性が違うのですから 混乱するのはやむなしと言えましょう。

ジェネリクス型パラメータの代入互換性

ジェネリクスでは、単に型をBと表現した場合、Bの階層だけが対象となります。

階層B

図のBの階層だけが対象になります。 ですから、代入できるのは<B>型だけです。

List<B> listB = new ArrayList<B>();

次に、<? extends B>と表現した場合、BとそのサブクラスであるCが含まれます。

階層? extends B

<? extends B>には<B>も<C>も代入することができます。 また、<? extends C>も代入することができます。

List<? extends B> listBEx;
listBEx = new ArrayList<B>();
listBEx = new ArrayList<C>();

List<? extends C> listCEx = new ArrayList<C>();
listBEx = listCEx;

また、ジェネリクスでは継承階層をスーパークラス側に遡る、<? super B>という記述もできます。 この場合は、<? extends B>とは逆方向の範囲をカバーします。

階層? super B

この<? super B>には<B>や<A>や<? super A>を代入することができます。

List<? super B> listBSu;
listBSu = new ArrayList<B>();
listBSu = new ArrayList<A>();

List<? super A> listASu = new ArrayList<A>();
listBSu = listASu;

このように、<>の内側と外側では異なる代入規則があることをまずは明確に意識してください。

posted @ 23:35 | Feedback (3176)