Продемонстрировать ковариантность и контравариантность в Java? [закрытый]
пожалуйста, покажите хороший пример для ковариации и контравариантности в Java.
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.