Продемонстрировать ковариацию и контравариантность в 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(). Другие языки поддерживают этот стиль контравариантности.
Дженерики
Это также возможно для Generics:
List<String> aList...
List<? extends Object> covariantList = aList;
List<? super String> contravariantList = aList;
Теперь вы можете получить доступ ко всем методам covariantList
это не принимает универсальный параметр (поскольку это должно быть что-то "расширяет объект"), но геттеры будут работать нормально (так как возвращаемый объект всегда будет иметь тип "объект")
Обратное верно для contravariantList
: Вы можете получить доступ ко всем методам с универсальными параметрами (вы знаете, что это должен быть суперкласс "String", поэтому вы всегда можете передать его), но нет получателей (возвращаемый тип может иметь любой другой супертип String)
Совместная дисперсия: Iterable и Iterator. Почти всегда имеет смысл определить ко-вариант Iterable
или же Iterator
, Iterator<? extends T>
можно использовать так же, как Iterator<T>
- единственное место, где появляется параметр типа, это тип возврата из next
метод, так что он может быть безопасно приведен к T
, Но если у вас есть S
продолжается T
Вы также можете назначить Iterator<S>
к переменной типа Iterator<? extends T>
, Например, если вы определяете метод поиска:
boolean find(Iterable<Object> where, Object what)
Вы не сможете позвонить с List<Integer>
а также 5
так что это лучше определить как
boolean find(Iterable<?> where, Object what)
Противопоставление: компаратор. Почти всегда имеет смысл использовать Comparator<? super T>
потому что это может быть использовано так же, как Comparator<T>
, Параметр типа отображается только как 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, тогда вы должны иметь возможность использовать B, когда требуется A.