Вопрос класса Java - PullRequest
       13

Вопрос класса Java

4 голосов
/ 23 апреля 2009
class One {
public One foo() { return this; }
}

class Two extends One {
public One foo() { return this; }
}

class Three extends Two {
public Object foo() { return this; }
}

public Object foo() { return this; } выдает ошибку компиляции. Это почему? Может кто-нибудь объяснить, почему тип «Объект» невозможен? Является ли Object базовым классом первого, второго класса? Если так, то почему выдает ошибку?

Пожалуйста, измените название вопроса, так как я не могу найти подходящее название.

Ответы [ 4 ]

16 голосов
/ 23 апреля 2009

Three.foo пытается переопределить Two.foo(), но не делает это правильно. Предположим, я должен был написать:

One f = new Three();
One other = f.foo();

Игнорируя тот факт, что на самом деле Three.foo() действительно возвращает One, подпись Three.foo() не гарантирует этого. Поэтому это не подходящее переопределение для метода, который должен возвращать One.

Обратите внимание, что вы можете изменить тип возвращаемого значения и переопределить его, но оно должно быть больше специфичным, а не меньше . Другими словами, это было бы хорошо:

class Three extends Two {
    public Three foo() { return this; }
}

потому что Three более конкретно, чем One.

5 голосов
/ 23 апреля 2009

Вы изменяете подпись метода foo способом, который не поддерживается. Полиморфизм работает только для другого списка аргументов, а не для идентичных методов, отличающихся только типом возвращаемого значения.

И если вы подумаете об этом, это вполне естественно ... Если бы это сработало, и кто-то, кто знает только об одном из двух суперклассов, вызвал бы Three.foo (), он ожидал, что он вернет единицу (потому что это то, как это работает в One и Two), но в Three вы можете на самом деле вернуть HashMap и при этом вести себя правильно.

Джон (в комментарии ниже) является правильным, вы можете сузить область, но тогда вы все равно будете следовать протоколу, что вы вернете «One» (если вы вернете Three из Three.foo ()), потому что подклассы будут все реализуют интерфейс суперкласса. Однако тип возвращаемого значения по-прежнему не является частью полиморфизма, поэтому у вас не может быть трех разных методов, которые отличаются только типом возвращаемого значения.

2 голосов
/ 23 апреля 2009

Переопределение метода и попытка вернуть менее конкретный тип является нарушением принципа замены Лискова , который говорит, что подклассы должны выполнять все контракты своего суперкласса. Ваш третий класс нарушает контракт суперкласса "foo () возвращает экземпляр One".

2 голосов
/ 23 апреля 2009

Это включит:

class Four extends Three {
public Object foo() { return "This String is not an instance of One"; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...