はじめに
<? extends E>や<? super E>が使われているクラスにどのような値が代入できるのか考えよう。
手っ取り早く結論を知りたい人は図解を見てください。
準備
2つのクラスA,Bがある。クラスBはクラスAのサブクラスであるとする:
class A {}
class B extends A {}
<? extends E>
<? extends E> はE型のすべてのサブクラスを表している。だから、<? extends A>が表すクラスは<? extends B>が表すクラスをすべて含んでいることがわかる。この性質があるので、以下の代入関係が成り立つ:
List<? extends A> listA;
List<? extends B> listB;
listA = listB; //OK
listB = listA; //コンパイルエラー
<? extends B>はクラスAを含んでいないので、listBにlistAを代入することはできない。代入できてしまうとキャストが必要になり、型安全でなくなってしまう。
また、<? extends E>はE型自身を含むので、以下の代入関係も成り立つ:
List<? extends A> list1;
List<A> list2;
list1 = list2; //OK
list2 = list1; //コンパイルエラー
<? super E>
<? super E> はE型のすべてのスーパークラスを表している。だから、<? super E>が表すクラスは<? super A>が表すクラスをすべて含んでいることがわかる。この性質があるので、以下の代入関係が成り立つ:
List<? super A> listA;
List<? super B> listB;
listA = listB; //コンパイルエラー
listB = listA; //OK
<? extends E>の場合と比較すると、継承関係と代入関係が逆になっていることに注意しよう。
また、<? super E>はE型自身を含むので、以下の代入関係も成り立つ:
List<? super A> list1;
List<A> list2;
list1 = list2; //OK
list2 = list1; //コンパイルエラー
<?>
<?> はすべてのクラスを表している。つまり、<? extends E>や <? super E>なども含めて、すべてのクラスを代入することができる。
List<?> list1;
List<? extends A> list2 = null;
List<? super A> list3 = null;
List<A> list4 = null;
list1 = list2; //OK
list1 = list3; //OK
list1 = list4; //OK
<? extends Object>
<? extends Object>は、Objectのサブクラスを表しているので、<?>と同じくすべてのクラスを表している。よって、<? extends E>とは異なり、<? super E>を代入することができる。
List<? extends Object> list1;
List<? extends A> list2 = null;
List<? super A> list3 = null;
List<A> list4 = null;
List<?> list5 = null;
list1 = list2; //OK
list1 = list3; //OK
list1 = list4; //OK
list1 = list5; //OK
図解
ここまでの代入関係を図にしてみると、以下のようになる。
矢印は、矢印の元が矢印の先に代入できることを表す。
直接1本の矢印でつながっていなくても、複数の矢印でつながっていれば代入できる。
参考
Java Language Specification 4.5.1. Type Arguments of Parameterized Types
https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.5.1