1. ホーム
  2. java

[解決済み] Javaにおける<? extends Class>と<? super Class> - なぜこのように動作するのでしょうか?

2022-03-09 15:26:22

質問

またまた初心者がJava Genericsを理解しようとしています。 私はすべてのトピックを観察し、私は見つけたが、私はまだ大きな疑問を持っています。 以下のことを説明していただけませんか?

  1. <? extends SomeClass> というのは ? は任意の型であり、かつ extends SomeClass のサブクラスでしかありえないことを意味します。 SomeClass . では、2つの基本クラスを書きます。
abstract class Person {
    private String name;
    public Person(String name) {
        this.name = name;
    }
}

class Student extends Person {
    public Student(String name) {
        super(name);
    }
}

クラス Student になります。 ? を、この例では ? extends Person 正確には そして、私はArrayListに新しい学生を追加しようとしている、私が上記の記述から理解するように、Personのサブクラスであるすべてのクラスが適用されます。

Student clarissa = new Student("Clarissa Starling");
List<? extends Person> list = new ArrayList<>();
list.add(clarissa); //Does not compile

とEclipseは言っています。

のメソッドadd(capture#3-of ? extends Person)を使用しています。 リストには適用できません。 引数(Student)"

どのようにすればクラス Student をパラメータとするListを宣言した場合、適用できません。 <? extends Person>Student はまさにクラスを拡張しています。 Person ?

とはいえ、次のようなコードになります。

List<? super Person> list = new ArrayList<>();
list.add(clarissa); 

がコンパイルされ、うまく動作します ( list.get(0) という正しい結果を示しています。 toString の呼び出し)。 私の理解では List<? super Person> は、このリストに任意の型を渡すことができることを意味します。 Person クラス(この場合、それは Object クラスのみ)。しかし、論理に反して、サブクラスの Student を簡単に List<? super Person> !

さて、私たちの感情はさておき、クラリッサ・スターリングが私たちのコレクションに加わることで何が起こるか見てみましょう。私たちのクラスを使ってみましょう Student そして、それにいくつかのメソッドを追加してください。

class Student extends Person {
    private int grant;
    public Student(String name) {
        super(name);
    }

    public void setGrant(int grant) {
        this.grant = grant;
    }

    public int getGrant() {
        return this.grant;
    }

}

次に、この更新されたクラスからインスタンス化されたオブジェクト (例えば、私たちのオブジェクト "clarissa") を、次のように渡します。 List<? extends Person> . こうすることで、サブクラスをそのスーパークラスのコレクションに格納できることを意味します。もしかしたら、私は根本的な考えを理解していないかもしれませんが、現段階では、サブクラスをそのスーパークラスのコレクションに追加することと、オブジェクト "clarissa" への参照を Person 型の変数に代入することに違いはないように思えます。スーパークラスの変数を使用して、そのうちの1つを処理したい場合、呼び出し可能なメソッドを同じように減らすことができます。では、なぜ List<? extends SomeClass> は同じように動作しません。 List<? super SomeClass> は逆に機能するのですか?

  1. との根本的な違いがわかりません。 <T> (または <E> またはJLSの適切な部分の他の文字)と <?> . どちらも <T><?> タイプホルダー では、なぜ同じ目的のために2つのキーワード(この記号はキーワードではなく、Java言語では両方の記号の重い意味を強調するためにこの言葉を使っただけです)を持っているのでしょうか?

どのように解決するのですか?

私の見方はこうです - プレースホルダーは T は明確な型を表し、実際の型を知る必要がある場所では、それを解決できるようにする必要があります。これに対して、ワイルドカードの ? は任意の型を意味し、その型が何であるかを知る必要は決してない。このように extendssuper の境界で、そのワイルドカードを何らかの方法で制限していますが、実際の型を取得する方法はありません。

ということは、もし私が List<? extends MySuper> であれば、私が知っているのは、その中のすべてのオブジェクトが MySuper インターフェイスを持ち、そのリストに含まれるすべてのオブジェクトは同じタイプです。その型が何であるかは知らないが、ただ、それが MySuper . ということは、そのリストからオブジェクトを取り出すのに必要なのは MySuper インターフェイスを使用します。コンパイラは、たとえ正しい型のオブジェクトを持っていたとしても、コンパイル時にそれを確認することができないからです。つまり、このコレクションはある意味、読み取り専用のコレクションなのだ。

がある場合、論理は逆になります。 List<? super MySuper> . ここでは、コレクションが、以下のスーパータイプである確定型であることを述べています。 MySuper . これはつまり、いつでも MySuper オブジェクトを追加します。しかし、実際の型が分からないので、オブジェクトを取り出すことはできません。つまり、書き込み専用のコレクションのようなものです。

境界付きワイルドカードと「標準的な」汎用型パラメータを使用する場合、その違いが明らかになり始める場所です。例えば、3つのクラスがあるとします。 Person , StudentTeacher である。 Person がベースになっています。 StudentTeacher を拡張します。APIの中で Person で、コレクションの各項目に対して何かをします。しかし、あなたが本当に気にするのは、そのコレクションが Person インターフェースで動作するはずです。 List<Student>List<Teacher> を同様に使用することができます。このようにメソッドを定義すると

public void myMethod(List<Person> people) {
    for (Person p: people) {
        p.doThing();
    }
}

を取ることはできません。 List<Student> または List<Teacher> . そこで、代わりに、次のように定義します。 List<? extends Person> ...

public void myMethod(List<? extends Person> people){
    for (Person p: people) {
        p.doThing();
    }
}

ということができます。 myMethod は決してリストに追加する必要はありません。そして今、あなたは List<Student>List<Teacher> は両方ともメソッドに渡すことができます。

さて、Studentをリストに追加する別のメソッドがあるとします。このメソッドのパラメータが List<Student> を取ることはできません。 List<People> でいいはずなのに。そこで List<? super Student>

public void listPopulatingMethod(List<? extends Student> source, List<? super Student> sink) {
    for (Student s: source) {
        sink.add(s);
    }
}

これはPECSの核心部分であり、詳しくは別のところでお読みいただくとして...。 PECS(Producer Extends Consumer Super)とは? http://www.javacodegeeks.com/2011/04/java-generics-quick-tutorial.html