質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

2174閲覧

Java ワイルドカードを使用したジェネリックスの指定について

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2017/03/17 04:38

編集2017/03/17 05:22

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も格納できないのではないでしょうか。

お手数ですがご指摘頂ければ幸いです。
どうぞよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

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型を継承した何か」
であることは明らかであるため、以下のコードは正常にコンパイルできます。

java

1BBB 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型の変数にしか代入する事ができません。

投稿2017/03/17 06:09

KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/03/17 06:36 編集

<? extends BBB>はBBB型を継承した?型を指定しており、BBB型には継承した?型で定義されているプロパティを持っているとは限らないため、代入するとコンパイルエラーとなる。 一方で、<? super BBB>はBBB型かそのスーパークラスを指定しており、BBB型はそのスーパークラスのプロパティやメソッドを持ち合わせているため、代入できる、という認識でよいでしょうか。 ご回答頂き、ありがとうございます。
KiyoshiMotoki

2017/03/17 06:44

上のコメントの「代入」は、「list1.add(x)」や「list2.add(x)」の事でしょうか? であれば、仰る通りです。
退会済みユーザー

退会済みユーザー

2017/03/17 07:08

はい、add()メソッドを指しております。 最後までご丁寧にご教授下さり、誠にありがとうございます。
guest

0

list1の実体のジェネリクス指定がCCCの場合、BBB型を入れられません。
このように、確実に入れられる保証がないため、コンパイルエラーになります。
逆に、list2のジェネリクス指定はBBBのサブクラス型で、その型がAAAであれ、Objectであれ、その型にBBB型を入れるのは問題ないため、コンパイルが通るのです。

投稿2017/03/17 05:08

編集2017/03/17 06:11
swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/03/17 06:34

<? extends BBB>はBBB型を継承した?型を指定しており、BBB型には継承した?型で定義されているプロパティを持っているとは限らないため、代入するとコンパイルエラーとなる。 一方で、<? super BBB>はBBB型かそのスーパークラスを指定しており、BBB型はそのスーパークラスのプロパティやメソッドを持ち合わせているため、代入できる、という認識でよいでしょうか。 ご回答頂き、ありがとうございます。
guest

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型を代入することができます。
ただしこれも暗黙的型変換の結果として可能になっている処理であり、個人的には可読性の観点からあまり使ったことのある書き方ではありません。

参考になるかも

投稿2017/03/17 05:04

編集2017/03/17 05:11
akabee

総合スコア1947

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/03/17 06:34

<? extends BBB>はBBB型を継承した?型を指定しており、BBB型には継承した?型で定義されているプロパティを持っているとは限らないため、代入するとコンパイルエラーとなる。 一方で、<? super BBB>はBBB型かそのスーパークラスを指定しており、BBB型はそのスーパークラスのプロパティやメソッドを持ち合わせているため、代入できる、という認識でよいでしょうか。 ご回答頂き、ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問