Продемонстрировать ковариантность и контравариантность в Java? [закрытый]

100
задан Paul Vargas 5 March 2015 в 21:04
поделиться

3 ответа

Ковариантность:

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 (). Другие языки поддерживают этот стиль контравариантности.

Generics

Это также возможно для Generics:

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

Теперь вы можете получить доступ ко всем методам covariantList , которые не принимают общий параметр (поскольку он должен быть что-то «расширяет Object»), но геттеры будут работать нормально (поскольку возвращаемый объект всегда будет иметь тип «Object»)

Обратное верно для contravariantList : вы можете получить доступ ко всем методам с общими параметрами (вы знаете, что это должен быть суперкласс String, поэтому вы всегда можете передать его), но без геттеров (возвращаемый тип может быть любого другого супертипа String)

147
ответ дан 24 November 2019 в 04:52
поделиться

Посмотрите на принцип замещения Лискова. По сути, если класс B расширяет класс A, то вы должны иметь возможность использовать B везде, где требуется A.

-3
ответ дан 24 November 2019 в 04:52
поделиться

Ковариация: Итерируемая и Итераторная. Почти всегда имеет смысл определить ковариант Iterable или Iterator. Iterator может использоваться так же, как Iterator - единственное место, где появляется параметр type, - это возвращаемый тип из метода next, поэтому его можно безопасно привести к T. Но если у вас есть S расширяет T, вы также можете назначить Iterator переменной типа Iterator. Например, если вы определяете метод find:

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

, вы не сможете вызвать его с помощью List и 5, поэтому его лучше определить как

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

Contra-variance: Comparator. Почти всегда имеет смысл использовать Компаратор, потому что его можно использовать так же, как Компаратор. Параметр type отображается только как тип параметра метода compare, так что T можно смело передавать ему. Например, если у вас есть DateComparator реализует Comparator { ... } и вы хотите отсортировать List с этим компаратором (java.sql.Date является подклассом java.util.Date), вы можете сделать с:

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

,но не с

<T> void sort(List<T> what, Comparator<T> how)
46
ответ дан 24 November 2019 в 04:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: