List<String> a1; ArrayList<Object> a2; ArrayList<? extends Object> a3;
こんな感じでListに関する変数が三つ定義されてるとします。さて、以下でコンパイルエラーになるのはどれ?
// 初期化
a1 = new ArrayList<String>();
a2 = new ArrayList<String>();
a3 = new ArrayList<String>();
// メソッド呼び出し
a1.add("hoge");
a2.add("hoge");
a3.add("hoge");なかなかわかりにくい挙動だと思うんですよねえ。。。o(゜^ ゜)
初期化はa2がエラーになります。Generic型が違う場合、たとえそれが継承関係でもキャストすらできません。主にセッターの事情だと思うんですが、a2の代入文を許してしまうと、このオブジェクトの内部に別の型*1を放り込むことが簡単に出来てしまい、型の一貫性が取れなくなります。
メソッド呼び出しはa3がエラーになります。a3は、例えば、IntegerをGeneric型とするArrayListである可能性もあるからです。
*1:Objectクラスを継承するもの全てOKなので