Пожалуйста, покажите хороший пример ковариации и контравариантности в Java.
источник
Пожалуйста, покажите хороший пример ковариации и контравариантности в Java.
Ковариация:
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 )
Ковариация: Iterable и Iterator. Почти всегда имеет смысл определить ковариант
Iterable
илиIterator
.Iterator<? extends T>
может использоваться так же, какIterator<T>
- единственное место, где появляется параметр типа, - это тип, возвращаемыйnext
методом, поэтому его можно безопасно преобразовать вT
. Но если у вас естьS
расширенияT
, вы также можете присвоитьIterator<S>
переменной типаIterator<? extends T>
. Например, если вы определяете метод поиска:вы не сможете вызвать его с помощью
List<Integer>
и5
, поэтому его лучше определить какКонтраверсия: компаратор. Его почти всегда имеет смысл использовать
Comparator<? super T>
, потому что его можно использовать так же, какComparator<T>
. Параметр типа отображается только как тип параметраcompare
метода, поэтомуT
его можно безопасно передавать. Например, если у вас есть,DateComparator implements Comparator<java.util.Date> { ... }
и вы хотите отсортировать егоList<java.sql.Date>
с помощью этого компаратора (java.sql.Date
является его подклассомjava.util.Date
), вы можете сделать это с помощью:но не с
источник
Посмотрите на принцип подстановки Лискова . Фактически, если класс B расширяет класс A, вы должны иметь возможность использовать B всякий раз, когда требуется A.
источник
contra variant
сказать.super.doSomething("String")
не может быть заменен наsub.doSomething(Object)
.