genericsのboundというか、?の動作
genericsのboundってよーわからんとのことなので、調子に乗って説明しちゃうぞ!
List<?>の動作
↓のコードがコンパイルエラーになるのはなんで?なんでなの?
private <T> void add(List<? extends T> list, T t){ list.add(t); } // ==> error // 型 List<capture#1-of ? extends T> のメソッド add(capture#1-of ? extends T) は 引数 (T) に適用できません。
一言で説明するとList<?>にはaddできません。これはList<?>とかList<? extends Hoge>は不定なインスタンス*1を持つわけで、addできるかわからないからだと思われます。
例えば、以下のコードで考えます。
public static void main(String[] args) { List<? extends java.util.Date> dateList = null; List<java.util.Date> utilDateList = new ArrayList<java.util.Date>(); List<java.sql.Date> sqlDateList = new ArrayList<java.sql.Date>(); dateList = utilDateList; //(1) dateList = sqlDateList; //(2) }
これはエラーなく通ります。
このとき、(1)の状態でのdateListのインスタンスはArrayList<java.util.Date>なので、そのインスタンスにはjava.util.Dateをaddできる。が、(2)の状態でのdateListのインスタンスはArrayList<java.sql.Date>なので、java.util.Dateはaddできない。つまり、List<? extends java.util.Date> dateListというモノに対して、java.util.Dateはaddできるかどうかわからない。だからjava的にはerrorとしてるわけなんでしょう。
↓のコードが通るのはなんで?なんでなの?
private <T, W extends T> void add(List<W> list, W w){ list.add(w); }
ということで、TとかWには関係ないので、このコードは通るわけです。
…なんて長々と説明しちゃいましたが、この辺りは[Java][Generics] Setとか[Java][Generics] SetとSetの違いまとめ - うなの日記がよくまとまっていて参考になると思います。
使いどころ
で、気になるList<?>の使いどころですが、例えば抽象メソッドの実装なんかで微妙に使えたりします。
import java.util.ArrayList; import java.util.List; public abstract class AbstractClass { public abstract List<? extends java.util.Date> newList(); //List<java.util.Date>だと、SubClass2#newListでerror //Listで型指定なしだと、通ることは通るんだけど。 //もちろん、getしたらjava.util.Dateクラスで受け取れる。 } class SubClass1 extends AbstractClass{ @Override public List<java.util.Date> newList() { return new ArrayList<java.util.Date>(); } } class SubClass2 extends AbstractClass{ @Override public List<java.sql.Date> newList() { return new ArrayList<java.sql.Date>(); } }
他にもあれば教えてください><
ちなみに、
List<?> list = new ArrayList<Object>()
もエラーになることから、宣言したときの方は一緒じゃないといけないんだろーなーっていう。
genericsのboundってよーわからん - ハタさんのブログ
うしろー!うしろー!
*1:と呼んでいいのかわかりませんが。