Почему в java-методе переопределение позволяет иметь ковариантные возвращаемые типы, а не ковариантные параметры?
Например, у меня есть базовый класс Processor с методом, который возвращает Object и принимает Object в качестве параметра. Я хочу расширить его и создать StringProcessor, который будет возвращать String и принимать String в качестве параметра. Однако ковариантная типизация допускается только с возвращаемым значением, но не с параметром. В чем причина таких ограничений?
class Processor {
Object process (Object input) {
//create a copy of input, modify it and return it
return copy;
}
}
class StringProcessor extends Processor {
@Override
String process (String input) { // permitted for parameter. why?
//create a copy of input string, modify it and return it
return copy;
}
}
2 ответа
Принцип Лискова. При разработке класса Processor вы пишете контракт, в котором говорится: "Процессор может принимать любой объект в качестве аргумента и возвращать объект".
StringProcessor является процессором. Так что он должен подчиняться этому контракту. Но если он принимает только String в качестве аргумента, он нарушает этот контракт. Помните: процессор должен принимать любой объект в качестве аргумента.
Так что вы должны быть в состоянии сделать:
StringProcessor sp = new StringProcessor();
Processor p = sp; // OK since a StringProcessor is a Processor
p.process(new Integer(3456));
Возвращая строку, он не нарушает контракт: он должен вернуть объект, строка - это объект, поэтому все в порядке.
Вы можете сделать то, что вы хотите достичь, используя дженерики:
class Processor<T> {
Object process (T input) {
//create a copy of input, modify it and return it
return copy;
}
}
class StringProcessor extends Processor<String> {
@Override
String process (String input) {
return copy;
}
}
Кроме того, если вы хотите получить теоретический ответ, причина этого заключается в том, что при рассмотрении отношения подтипа для типов функций отношение является ковариантным для возвращаемых типов, но противоречивым для типов аргументов (т.е. X -> Y
это подтип U -> W
если Y
это подтип W
а также U
это подтип X
).