Вопрос-ответ

Give examples of functions which demonstrate covariance and contravariance in the cases of both overloading and overriding in Java? [closed]

Приведите примеры функций, которые демонстрируют ковариацию и контравариантность в случаях как перегрузки, так и переопределения в Java?

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

Переведено автоматически
Ответ 1

Ковариация:

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", поэтому вы всегда можете передать один), но без геттеров (возвращаемый тип может быть любого другого супертипа String).

Ответ 2

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

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

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

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

Contra-variance: Comparator. Его почти всегда имеет смысл использовать 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)
Ответ 3

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

java