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

Другие вопросы по тегам