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


пожалуйста, покажите хороший пример для ковариации и контравариантности в Java.

3 84

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 (но, опять же, заполняет контракт Супер#сделать)

Примечание: этот пример не работает в Java. Компилятор Java будет перегружать и не переопределять doSomething () - метод. Другие языки поддерживают этот стиль контравариантности.

дженериков

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

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

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

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

Co-variance: Iterable и Iterator. почти всегда имеет смысл определить ко-вариант Iterable или Iterator. Iterator<? extends T> может использоваться так же, как Iterator<T> - единственное место, где появляется параметр type, - это тип возврата из next метод, поэтому его можно безопасно привести к T. Но если у вас есть S выходит T, вы также можете назначить Iterator<S> переменной типа Iterator<? extends T>. Например, если вы определяете метод find:

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

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

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

Contra-дисперсия: компаратор. это почти всегда имеет смысл использовать Comparator<? super T>, потому что его можно использовать так же, как Comparator<T>. Параметр type отображается только как compare тип параметра метода, так T можно безопасно передать к нему. Например, если у вас есть DateComparator implements Comparator<java.util.Date> { ... } и вы хотите отсортировать List<java.sql.Date> С, что компаратор (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)

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