Comments 12
И как часто вам приходилось с такими вот финтами ушами играться, что это породило данную статью)) Просто розовые пони и драконы не существуют — точно также как и ваши примеры в реальной работе. Или статья заключается именно в этом?
Number firstNum(List<? extends Number> xs) {
return xs.get(0);
}
Мы сразу теряем информацию о том, какой был тип, и после вызова метода нам снова нужно будет его скастовать явно. В шарпе я бы написал что-то типа
T firstNum<T>(List<T> xs) where T : Number {
return xs[0];
}
Который читается как «для любого списка элементов подтипа Number вернуть значение того же типа». Разве в джаве так нельзя указать? Я попробовал
<? extends Number> firstNum(List<? extends Number> xs) {
return xs.get(0);
}
Но это вроде не то же самое.
В каком то смысле информация действительно теряется, но в данном контексте она и не нужна. Если нужно сохранение типа, то можно написать такой код:
<T extends Number> T firstNum(List<T> xs) {
return xs.get(0);
}
Но я приводил пример не с этой целью. Рассмотрим такой код:
void query(Map<String, Object> parameters) { ... }
Метод принимает ассоциативный массив "параметров", значения которых могут иметь произвольные типы. Но если вдруг у нас в коде есть объект типа Map<String, String>
, то мы не сможем передать его в метод query
(типы не совпадают).
При этом если изменить сигнатуру метода на void query(Map<String, ? extends Object> parameters)
, то в него легко можно будет передать Map
с любым типом значений, включая Map<String, String>
.
void Foo<T>(Dictionary<string, T> dictionary) {}
Ковариация интересна в рамках работы в теле одного метода, не пересекая его. Например:
void Main()
{
IFoo<Object> iobj = null;
IFoo<String> istr = null;
// Присваивание работает благодаря ковариации
iobj = istr;
}
interface IFoo<out T>
{
T SomeValue { get;}
}
В этом случае через дженерики такой выразить не получится. Ну и классический случай, что массив значений X может безопасно считаться readonly-коллекцией базового типа
IEnumerable<object> foos = new int[] {1,2,3};
Тьюринг-полнота Generic типов Java