理系学生日記

おまえはいつまで学生気分なのか

? extends E と ? super E は結局見方の違いだった

先日ぼくはジェネリクスとかわかるしみたいなことを書いたけど、もちろんこんなのはデタラメだし、わかってるわけがありません。ぼくがこんな風に簡単にウソをつくことに対して、烈火のごとく怒りだしたりする人もいらっしゃるとおもいますけど、まず怒る前にまわりを見渡そうではありませんか。みてみろ、世の中ウソばっかしです!!
ブログ毎日書きますみたいなことを言ってた人のブログはいきなり更新が滞ってるし、今年の阪神は強いとか聞いてたのに単独 5 位だし、研修の講師の人に ? super E てどんなときに使うんですかとか聞いたらあんまし使いませんねとか言われて、ふんふんそうなのかーとか思ってたらいきなし 重要そうなところで出てきたりする。こんな風に世の中というのはウソばっかしですから、ぼくがちょびっとウソをついたところで、誤差の範囲内だし、地球には大した影響はありません。ましてや宇宙単位でみると、ぼくのウソとか気づかないレベルだし、そういうのに怒りを覚えるのははっきり言ってムダですから、さっさと忘れて家でゴロゴロすると良いと思います。

? extends E

プログラミング Java とか読んでても、? extends E はわりかし直感的に理解がいきました。
例えば以下のコードはコンパイルエラーになります。

import java.util.*;
class Parent {}
class Child extends Parent {}
public class TestExtends {
    public static void main(String[] args) {
        Set<Child>  childSet  = new HashSet<Child>();
        Set<Parent> parentSet = new HashSet<Parent>();
        parentSet = childSet; // error
    }
}

これは、例えエレメントに継承関係があったとしても、エレメントが異なっているコレクションには代入互換性がないからですね。ですから、もし HashSet のコンストラクタが

public HashSet(Collection<? extends E> c)

ではなく、

public HashSet(Collection<E> c)

だったら、

Hashset<Parent> parentSet = new HashSet<Parent>( childSet );

なんてのも、HashSet と HashSet の間に代入互換性がないもんだから、コンパイルできなくなる。こんなのができないと、ポリモルフィズムとか夢のまた夢なかんじですから、? extends E は必要ですね。

? super E

というわけで、? extends E はスッキリと理解がいったんですけど、? super E というのがなかなか納得いかなかった。なにこれ必要なの、いや、いらないよね、みたいなかんじに思ってたんですけど、結局のところ、? extends E と全く同じ理由で必要なんだなって気づきました。
上の対比でいうと、ホントはないけど

childSet.addTo( parentSet ) // childSet 中の Child を parentSet に加える

みたいなことをしたいときに必要になるんですね。これをしようと思うと、

public void addTo(Collection<? super E> c)

ってしとかないとコンパイルエラーになる。

てわけで、ちょっぴしスッキリした。