web-dev-qa-db-ja.com

Javaで共分散と反分散を示しますか?

Javaの共分散と反分散の良い例を示してください。

98
JavaUser

共分散:

class Super {
  Object getSomething(){}
}
class Sub extends Super {
  String getSomething() {}
}

Sub#getSomethingは、Super#getSomethingの戻り値型のサブクラスを返すため、共変です(ただし、Super.getSomething()のコントラクトをフルフィルします)

反分散

class Super{
  void doSomething(String parameter)
}
class Sub extends Super{
  void doSomething(Object parameter)
}

Sub#doSomethingは、Super#doSomethingのパラメーターのスーパークラスのパラメーターを取るため、反変です(ただし、Super#doSomethingのコントラクトを完全に埋めます)。

注意:この例はJavaでは機能しません。 Javaコンパイラーはオーバーロードし、doSomething()-Methodをオーバーライドしません。他の言語はこのスタイルの矛盾をサポートします。

ジェネリック

これはジェネリックでも可能です:

List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;

ジェネリックパラメーターを受け取らないcovariantListのすべてのメソッドにアクセスできるようになりました(mustは「オブジェクトを拡張する」必要があるため) 、しかし、ゲッターは正常に動作します(返されるオブジェクトは常に「Object」タイプであるため)

contravariantListの場合は逆です:ジェネリックパラメーターを使用してすべてのメソッドにアクセスできます( "String"のスーパークラスでなければならないため、常に1つを渡すことができます)。 Stringの他のスーパータイプの)

144
Hardcoded

共分散:IterableおよびIterator。共変IterableまたはIteratorを定義することはほとんど常に意味があります。 Iterator<? extends T>Iterator<T>と同じように使用できます-型パラメーターが表示される場所はnextメソッドからの戻り型のみであるため、Tに安全にアップキャストできます。ただし、STを拡張している場合は、Iterator<S>Iterator<? extends T>型の変数に割り当てることもできます。たとえば、findメソッドを定義している場合:

boolean find(Iterable<Object> where, Object what)

List<Integer>および5で呼び出すことはできないため、次のように定義する方が適切です。

boolean find(Iterable<?> where, Object what)

コントラバリアンス:コンパレータComparator<? super T>と同じように使用できるため、Comparator<T>を使用することはほとんど常に意味があります。 typeパラメーターはcompareメソッドパラメータータイプとしてのみ表示されるため、Tを安全に渡すことができます。たとえば、DateComparator implements Comparator<Java.util.Date> { ... }があり、List<Java.sql.Date>をそのコンパレーターで並べ替える場合(Java.sql.DateJava.util.Dateのサブクラスです)、次のようにできます。

<T> void sort(List<T> what, Comparator<? super T> how)

ではなく

<T> void sort(List<T> what, Comparator<T> how)
45
Yardena