Продемонстрировать ковариантность и контравариантность в 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 (но, опять же, заполняет контракт Super#doSomething)
Примечание: этот пример не работает в Java. Компилятор Java будет перегружать, а не переопределять метод doSomething () -. Другие языки поддерживают этот стиль противопоставления.
дженериков
Это также возможно для дженерики:
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
теперь вы можете получить доступ ко всем методам covariantList
это не принимает общий параметр (как это должны быть чем-то "расширяет объект"), но геттеры будут работать нормально (так как возвращаемый объект всегда будет иметь тип "Object")
наоборот contravariantList
: вы можете получить доступ ко всем методам с общими параметрами (вы знаете, что это должен быть суперкласс "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
тип параметра метода, so 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, вы должны иметь возможность использовать B всякий раз, когда требуется A.