[解決済み] Javaにおける<? extends Class>と<? super Class> - なぜこのように動作するのでしょうか?
質問
またまた初心者がJava Genericsを理解しようとしています。 私はすべてのトピックを観察し、私は見つけたが、私はまだ大きな疑問を持っています。 以下のことを説明していただけませんか?
-
<? 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>
は逆に機能するのですか?
-
との根本的な違いがわかりません。
<T>
(または<E>
またはJLSの適切な部分の他の文字)と<?>
. どちらも<T>
と<?>
は タイプホルダー では、なぜ同じ目的のために2つのキーワード(この記号はキーワードではなく、Java言語では両方の記号の重い意味を強調するためにこの言葉を使っただけです)を持っているのでしょうか?
どのように解決するのですか?
私の見方はこうです - プレースホルダーは
T
は明確な型を表し、実際の型を知る必要がある場所では、それを解決できるようにする必要があります。これに対して、ワイルドカードの
?
は任意の型を意味し、その型が何であるかを知る必要は決してない。このように
extends
と
super
の境界で、そのワイルドカードを何らかの方法で制限していますが、実際の型を取得する方法はありません。
ということは、もし私が
List<? extends MySuper>
であれば、私が知っているのは、その中のすべてのオブジェクトが
MySuper
インターフェイスを持ち、そのリストに含まれるすべてのオブジェクトは同じタイプです。その型が何であるかは知らないが、ただ、それが
MySuper
. ということは、そのリストからオブジェクトを取り出すのに必要なのは
MySuper
インターフェイスを使用します。コンパイラは、たとえ正しい型のオブジェクトを持っていたとしても、コンパイル時にそれを確認することができないからです。つまり、このコレクションはある意味、読み取り専用のコレクションなのだ。
がある場合、論理は逆になります。
List<? super MySuper>
. ここでは、コレクションが、以下のスーパータイプである確定型であることを述べています。
MySuper
. これはつまり、いつでも
MySuper
オブジェクトを追加します。しかし、実際の型が分からないので、オブジェクトを取り出すことはできません。つまり、書き込み専用のコレクションのようなものです。
境界付きワイルドカードと「標準的な」汎用型パラメータを使用する場合、その違いが明らかになり始める場所です。例えば、3つのクラスがあるとします。
Person
,
Student
と
Teacher
である。
Person
がベースになっています。
Student
と
Teacher
を拡張します。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
関連
-
[解決済み] ヘッドリカーシオンとテールリカーシオンの違い [重複]について
-
[解決済み] JavaにおけるHashMapとHashtableの違いは何ですか?
-
[解決済み] Javaにおけるpublic、protected、package-private、privateの違いは何ですか?
-
[解決済み] serialVersionUIDとは何ですか、またなぜそれを使用する必要がありますか?
-
[解決済み] リフレクションとは何か、なぜ有用なのか?
-
[解決済み] Javaで配列を宣言し、初期化する方法は?
-
[解決済み] Javaにおける "implements Runnable "と "extends Thread "の違いについて
-
[解決済み] Java の配列を表示する最も簡単な方法は何ですか?
-
[解決済み] Java内部クラスと静的ネストされたクラス
-
[解決済み】PECS(Producer Extends Consumer Super)って何?)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] java.sql.SQLException: ORA-00933: SQL コマンドが正しく終了していません。
-
[解決済み] Firebase クラスにシリアライズするプロパティが見つからない
-
[解決済み] 環境変数JAVA_OPTSの使い方を教えてください。
-
[解決済み] javacが「using unchecked or unsafe operations」という警告を出す原因は何ですか?
-
[解決済み] mavenのコンパイルに失敗するのはなぜですか?
-
[解決済み] javaでAnnotation Inheritanceのようなものはあるのでしょうか?
-
[解決済み] スリーピング中のスレッドが割り込まれ、データベースへの接続が失われる
-
[解決済み] タイプの安全性。アンチェック・キャスト
-
[解決済み] init-paramとcontext-param
-
[解決済み】PECS(Producer Extends Consumer Super)って何?)