凪瀬 Blog
Programming SHOT BAR

目次

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

書庫

日記カテゴリ

 

いらっしゃいませ。今日は皆さんわんくま勉強会でしてねぇ。当BARも閑古鳥なんですよ。

でもまぁせっかくですし前回の クイズの続きと行きましょう。Javaのジェネリクスの自信のほどはいかがですか?

前回は

List<String> listA = new ArrayList<String>();
List<? extends Object> listB = listA;
listB.add(new Object());

というコードでlistB = listAの代入はできるものの、listB.add()でコンパイルエラーとなるということでした。
では、次のコードをコンパイルおよび実行しようとするとどうなるでしょう?

List<Object> listA = new ArrayList<Object>();
List<? super String> listB = listA;
listB.add(new String());

正解は、何事もなく動くのです。

見慣れないかもしれませんが、ジェネリクスでは<? super ~>というように、 ある型をサブクラスとする何か、という表現ができます。extendsと逆ですね。
そして、今の場合はlistBはStringの親となる型であれば何でも格納できます。

前回との対比でString型としましたが、String型はfinalですので説明しやすい型に差し替えて説明いたしましょう。
以下に出てくるクラスは C extends B、 B extends Aとなっています。Aが一番上で、Bはそのサブクラス、Cはさらにそのサブクラスです。

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

List<? extends B> list1;
list1 = listA; // NG
list1 = listB; // OK
list1 = listC; // OK
list1.add(new A())// NG
list1.add(new B())// NG
list1.add(new C())// NG

List<? super B> list2;
list2 = listA; // OK
list2 = listB; // OK
list2 = listC; // NG
list2.add(new A())// NG
list2.add(new B())// OK
list2.add(new C())// OK

list1への代入はlistBとlistCだけOKです。 <? extends B>ですから、「Bを継承した何か」が格納されるListです。 listAはAが格納されています。AはBの親ですから、Bを継承していませんから当然NGです。

list1へのadd()がややこしいのですが、list1にはList<B>もList<C>も代入できます。 Cを継承したクラスがあればさらにそれらを格納するListも代入することが出来ますね。
そしてlist1.add()はこれらすべてに対して問題のない型しか格納できない理屈になります。 List<B>にもList<C>にもC型ならadd()できますが、継承は下へ下へと広がっていくものですから、 さらに継承階層が増える可能性がある以上、C型のadd()も認めるわけにはいきません。

かくして<? extends B>には何もadd()することができなくなるのです。

しかし、list2の方は趣が違っています。 <? super B>ですから、「Bの親の何か」なら格納できます。 ですから今度はlistAとlistBが代入できるようになります。ここまでは単にlist1のときの逆になっただけですね。

ここからが重要です。 list2に代入できるListはBで最後です。今回はA-B-Cの3段階の継承ですが、 100段階の継承だろうとsuperで明示された階層より下の型は代入できません。

ということは、Listの方の最下層であるBよりも継承階層が下の型はadd()しても大丈夫なんです。 listAにもlistBにもB型やC型は代入できます。listAよりも上の階層のListがきたって当然B型もC型も代入できます。 だから<? super ~>のときは指定した型より 下の階層のオブジェクトならadd()することができるのですね。

投稿日時 : 2007年8月4日 23:06
コメント
  • # re: ジェネリクスと代入と落とし穴2
    かつのり
    Posted @ 2007/08/04 23:30
    実は<? super Foo>は苦手。イメージしにくいですね。
    これに慣れるとジェネリクスを極めたといっても過言じゃないんでしょうね。

    そういやJDK7から型パラメータにどの型が設定されているかを、
    ランタイムで取得できるようにするというような話がでていましたが、
    どうなるんでしょうね・・・

    class Foo<T>{}
    というクラスがあって、new Foo<String>やnew Foo<Bar>とかかれたときに、
    Fooの中でStringやBarを知る手段が提供されるかもしれないって話です。
  • # re: ジェネリクスと代入と落とし穴2
    凪瀬
    Posted @ 2007/08/05 0:29
    どういう仕組みなんでしょうかねぇ。
    いままではコンパイラでの対応だったわけですが…。
    実行時に取得できるとなるとクラスの方に仕掛けがあるのでしょうか。
  • # ジェネリクスと代入と落とし穴3
    凪瀬 Blog
    Posted @ 2007/08/05 16:12
    ジェネリクスと代入と落とし穴3
  • # re: ジェネリクスと代入と落とし穴2
    シャノン
    Posted @ 2007/08/05 22:24
    面白いですねぇ。
    Eiffelが仕様に矛盾を抱えているCATCALL問題をうまく解決しているようです。

    ところで、ジェネリックコレクションの大きなメリットは、取り出すときに型キャストが要らないことですが、list2から要素を取り出すときの戻り値の型は何になってるんです?
  • # re: ジェネリクスと代入と落とし穴2
    凪瀬
    Posted @ 2007/08/05 22:45
    list2.get()の戻り型はObjectです。
    B型をサブクラスとする何かですから、継承階層のてっぺんのObject型以外へは安全にキャストできません。
  • # re: ジェネリクスと代入と落とし穴2
    シャノン
    Posted @ 2007/08/06 0:26
    ふむ、やっぱりそうなりますか。

    ちなみに、「継承関係とは、クラスをオブジェクトの集合と捉えた場合の、部分集合の関係である」という立場に立つと、

    A is-a B の時、成り立つのは
    List<A> is-a List<B> ではなくて、
    List<A> is-a List<?> だと思います。

    VBが今後、このあたりの問題をどう扱うのかも興味深いです。
  • # re: 長い型を記述するのが面倒くさい
    R.Tanaka.Ichiro's Blog
    Posted @ 2007/12/11 13:24
    re: 長い型を記述するのが面倒くさい
  • # アスペクト指向の概念
    凪瀬 Blog
    Posted @ 2008/03/25 10:34
    アスペクト指向の概念
  • # 段々わかってきました。
    イートレード
    Posted @ 2011/12/09 2:27
    型の問題は、もともとつまづきやすい点です。
    慣れが必要ですね。
  • # My brother recommended I might like this web site. He was totally right. This post truly made my day. You cann't imagine simply how much time I had spent for this info! Thanks!
    My brother recommended I might like this web site.
    Posted @ 2021/09/06 3:40
    My brother recommended I might like this web site.
    He was totally right. This post truly made my day. You cann't imagine simply how much
    time I had spent for this info! Thanks!
  • # You really make it seem really easy together with your presentation however I to find this topic to be actually something that I feel I'd by no means understand. It kind of feels too complex and extremely vast for me. I am taking a look ahead to your ne
    You really make it seem really easy together with
    Posted @ 2021/09/11 11:01
    You really make it seem really easy together with your presentation however I
    to find this topic to be actually something that I feel I'd by no means understand.

    It kind of feels too complex and extremely vast for me.

    I am taking a look ahead to your next put up, I will attempt to get the hold of it!
    quest bars http://bit.ly/3jZgEA2 quest bars
  • # Inspiring quest there. What occurred after? Take care!
    Inspiring quest there. What occurred after? Take c
    Posted @ 2021/10/25 23:55
    Inspiring quest there. What occurred after?

    Take care!
  • # Inspiring quest there. What occurred after? Take care!
    Inspiring quest there. What occurred after? Take c
    Posted @ 2021/10/25 23:56
    Inspiring quest there. What occurred after?

    Take care!
タイトル
名前
Url
コメント