Java ワイルドカードを使用したジェネリックスの指定について
- 評価
- クリップ 1
- VIEW 1,392

退会済みユーザー
Javaにおける、ワイルドカードを使用したジェネリックスの指定についての質問です。
ある書籍で書かれていた内容が理解できなかったため、質問させていただきます。
以下のようなコードがあります。
import java.util.*;
class AAA {}
class BBB extends AAA {}
class CCC extends BBB {}
public class Main {
public static void main(String[] args) {
List<? extends BBB> list1 = new List<? extends BBB>();
List<? super BBB> list2 = new List<? super BBB>();
}
}
このとき、list1には<BBB>や<CCC>をジェネリックスで指定したコレクションを代入することができ、list2には<BBB>や<AAA>をジェネリックスで指定したコレクションを代入することができる認識です。
書籍には、
「list.add(new BBB());
→list1の場合、BBBのエレメントを格納することができないため、上記コードはコンパイルエラーが発生する」
との記述があるのですが、この内容が理解できませんでした。
list1の型パラメータは<? extends BBB>であり、上記認識の通り、<BBB>を代入できるのではないかと考えております。
<追記>
ご回答頂きありがとうございます。
疑問点を1点、追加させていただけないでしょうか。
list2の場合は
「list.add(new BBB());」
がコンパイルエラーにならない理由もご教授頂けないでしょうか。
もし型パラメータ<? extends BBB>のlist1にBBBを格納できないのであれば、<? super BBB>のlist2も格納できないのではないでしょうか。
お手数ですがご指摘頂ければ幸いです。
どうぞよろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+3
List<? extends BBB> list1
を日本語に言い換えると、
「変数 list1 は、BBB型を継承した何かをジェネリックス型に持つ List型である」
となります。
実際、変数 list1 には List<BBB>型のオブジェクトだけでなく、List<CCC>型のオブジェクトや他のあらゆる List<XXX>型(XXX は BBB型を拡張したあらゆる型)のオブジェクトを代入できるようになります。
しかし、コンパイラには、list1.add(new BBB())
を実行する時点で list1 に何が代入されているかは分かりません。
(ソースコード全体を検査すれば分かるかも知れませんが、コンパイラはそこまで親切ではありません)
もし、list1 に List<CCC>型のオブジェクトが代入されていた場合、list1.add(new BBB())
が実行できない事は分かりますね?
そのため、コンパイラはlist1.add(new BBB())
をコンパイルエラーとします。
一方、list1 から取り出したオブジェクトが
「BBB型を継承した何か」
であることは明らかであるため、以下のコードは正常にコンパイルできます。
BBB b = list1.get(n); // n は int型の変数
「list.add(new BBB());」
がコンパイルエラーにならない理由
は
「list2.add(new BBB());」
がコンパイルエラーにならない理由
ですね?
これについては、List<? super BBB> list2
を上の説明にならって日本語に言い換えてみると、分かるはずです。
list2 には (BBB型を含む)BBB型を継承したあらゆる型のオブジェクトをadd()
できる反面、
list2.get(n)
の戻り値は、Object型の変数にしか代入する事ができません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
list1の実体のジェネリクス指定がCCCの場合、BBB型を入れられません。
このように、確実に入れられる保証がないため、コンパイルエラーになります。
逆に、list2のジェネリクス指定はBBBのサブクラス型で、その型がAAAであれ、Objectであれ、その型にBBB型を入れるのは問題ないため、コンパイルが通るのです。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
list.add(new BBB());
上記コードはlistに対しBBB型を格納しようとしています。
一方、宣言時にはnew List<? extends BBB>()と宣言しており、この宣言ではListの型としてBBB型を継承した?型を指定しています。
List1の要素の型には?型が指定されていますので、BBB型は指定できません。?型はBBB型を継承した?型であり、BBB型ではありません。
具体例で考えます。Humanクラスを継承したDancerクラスがあるとします。Dancerクラスは、Humanクラスのプロパティ(年齢)やメソッド(食べる、寝る)に加えて、異なるプロパティ(専門ダンス:バレエ、ブレイク)やメソッド(踊る)を持っているとします。
List<Dancer>()と宣言した場合、HumanはDancerで追加されたプロパティやメソッドは持っていませんので、格納できるとすると問題があります。
List(0)にDancer型、List(1)にHuman型を格納したとします。その場合、List(0)は踊ることができ、List(1)は踊ることができないことになります。Humanは踊るというメソッドを持っていませんので。
よって両者を混在させるわけにはいかず、コンパイル時にエラーにしてくれています。Human型とDancer型は異なるものであるということです。
逆に、DancerクラスはHumanクラスを継承しており、Humanクラスの持つプロパティやメソッドを持っていますので、Human型に対してはDancer型を代入することができます。
ただしこれも暗黙的型変換の結果として可能になっている処理であり、個人的には可読性の観点からあまり使ったことのある書き方ではありません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.10%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/03/17 15:36 編集
一方で、<? super BBB>はBBB型かそのスーパークラスを指定しており、BBB型はそのスーパークラスのプロパティやメソッドを持ち合わせているため、代入できる、という認識でよいでしょうか。
ご回答頂き、ありがとうございます。
2017/03/17 15:44
であれば、仰る通りです。
2017/03/17 16:08
最後までご丁寧にご教授下さり、誠にありがとうございます。