なるべく直感的に分かり易すそうな説明を試みます。
ワイルドカードとはどの要素が来てもいいように設定しているものであると認識しています。
ちょっと違います。どのようなものも要素に許す宣言はワイルドカードを使うまでもなくList<Object>
と宣言すれば事足ります。こう宣言すれば「どんな型の要素でも入るリスト」になります。(※)
List<?>
って何の意味があるといえば、「要素型がObject以外のなにかの型」つまり「要素の型についてなんらかの制約があるリスト」のうち「どんな制約が付いているかが不明だけどListであることだけは分かっている」という意味合いです。
Java
1void acceptStringList(List<String> list) {
2 ...
3}
4
5void acceptAnyKindOfList(List<?> list) {
6 Object a = list.get(0); // (A)OK
7 list.add(追加すべき要素); // (B)NG
8}
9
10...
11
12acceptStringList(new ArrayList<String>()); // OK
13acceptStringList(new ArrayList<Integer>()); // NG
14
15acceptAnyKindOfList(new ArrayList<String>()); // OK
16acceptAnyKindOfList(new ArrayList<Integer>()); // OK
こんなふうになります。acceptAnyKindOfListメソッドは引数にどんな制約付きのListでも渡せますが、何が渡されるかは不明という点に注意してみてください。
このメソッドでは「要素の制約が分かってなくても行える操作」ならできます。例えば要素の取り出し(A)は行えます。制約はわからなくても「絶対にObjectの派生の何かであることは確か」なので。
一方「要素の制約が分かっていないと行えない操作」例えば要素の追加(B)はできません。List<String>なのかList<Integer>なのかあるいはそれ以外の何の型なのかがわからなければ「要素として格納してよい要素の型を特定できない」ため追加すべき要素
の型を表現しようがないのです。型安全であることが静的型付け言語の命なわけですから、こういう仕様になっているのは当然と言えましょう。
※: どんな型の要素でも入る
厳密に言えば参照型の要素なら入るというべきかも知れません。primitive型は含まれませんので。しかしそもそもprimitive型が格納できるList(より一般的にはコレクション)は存在しませんので、本件の議論では「どんな型でも」という表現は「どんな参照型でも」というふうに考えてください。
追記:本件は「ジェネリクスの変性」「共変、反変、非変」といったキーワードに関係が深いトピックだと思います。変性についての話はややこしく感じますが、ある程度把握しておくとジェネリクスを用いたAPIの型宣言の意味がより的確にわかってくるので調べてみることをお勧めします。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/20 11:18
2018/01/20 12:03
2018/01/20 13:48
2018/01/20 18:23
2018/01/20 18:59
2018/01/20 19:01
2018/01/20 19:09 編集