Javaでオーバーロードとオーバーライドの両方のケースで共分散と反分散を示す関数の例を挙げてください。[閉まっている]


105

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

回答:


155

共分散:

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

Super#getSomethingの戻り型のサブクラスを返すため、Sub#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()メソッドをオーバーロードし、オーバーライドしません。他の言語は、このスタイルの反変をサポートしています。

ジェネリック

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

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

これでcovariantList、ジェネリックパラメーターをとらないすべてのメソッドにアクセスできます(「オブジェクトを拡張する」ものである必要があるため)。ただし、ゲッターは正常に動作します(返されるオブジェクトは常に「オブジェクト」型であるため)

反対の場合は当てはまりますcontravariantList。ジェネリックパラメーターを使用してすべてのメソッドにアクセスできます( "String"のスーパークラスである必要があるため、常に1つ渡すことができます)。 )


79
最初の反変の例は、Javaでは機能しません。SubクラスのdoSomething()はオーバーロードであり、オーバーライドではありません。
クレイグP.モトリン

15
確かに。Javaはサブタイピングで反変引数をサポートしていません。(最初の例のように)メソッドの戻り値の型に関する共分散のみ。
the_dark_destructor

すばらしい答えです。共分散は私には論理的に見えます。しかし、矛盾を説明するJLSの段落を教えていただけませんか。なぜSub.doSomethingが呼び出されるのですか?
ミハイル、

2
クレイグが指摘したように、そうではありません。私はここでオーバーライドとオーバーロードの間に衝突があると思います。SUNは(いつものように)下位互換性のあるオプションを選択しました。したがって、Javaでは、メソッドをオーバーライドするときに反変パラメーターを使用できません。
14:47にハードコード

1
なぜ私が私の回答に反対票を投じるのかを知って嬉しいです。
2015年

48

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

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

List<Integer>and 5で呼び出すことはできないので、次のように定義することをお勧めします

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

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

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

ではなく

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

-4

リスコフの代替原理を見てください。実際、クラスBがクラスAを拡張する場合、Aが必要なときはいつでもBを使用できるはずです。


6
これは質問に答えておらず、誤解を招くものです。セマンティックの正確性を損ない、したがってLSPに違反するバリアントシステムを設計することは完全に可能です。
Matt Whipple 2016

これはcontra variant言うまでもありません。super.doSomething("String")に置き換えることができませんでした sub.doSomething(Object)
2017年

問題ではありません
OlivierTerrien
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.