Продемонстрировать ковариантность и контравариантность в 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.