tags:

views:

134

answers:

4
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; } throws a compilation error. Why is that? Can someone explain why "Object" type is not possible? Is Object the base class of Class One, Two? If So why does it throws an error?

Please change the title of the question as I couldnt find a suitable title.

+4  A: 

You are changing the signature of the foo method in a way not supported. Polymorphism only works for different argument list, not for identical methods only different by the return type.

And if you think about it, it is quite natural... If it worked and someone who only knows about one of the two super classes would call Three.foo() he would expect it to return a One (because that is how it works in One and Two) but in Three you could actually return a HashMap and still behave correctly.

Jon (in the comment below) is correct, you can narrow the scope but then you would still follow the protocol that you will return a "One" (should you return a Three from Three.foo()) because subclasses will all implement the superclass interface. However, return type is still not part of the polymorphism, hence you cannot have three different methods that only differs by return type.

Fredrik
Not true. You can override by making the return type *more* specific.
Jon Skeet
I was about to say that in an edit but you were two quick for me :-)
Fredrik
+14  A: 

Three.foo is trying to override Two.foo(), but it doesn't do it properly. Suppose I were to write:

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

Ignoring the fact that actually Three.foo() does return a One, the signature of Three.foo() doesn't guarantee it. Therefore it's not an appropriate override for a method which does have to return a One.

Note that you can change the return type and still override, but it has to be more specific rather than less. In other words, this would be okay:

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

because Three is more specific than One.

Jon Skeet
+1  A: 

It would enable:

class Four extends Three {
public Object foo() { return "This String is not an instance of One"; }
}
Stephen Denne
+1  A: 

Overriding a method and trying to return a less specific type is a violation of the Liskov substitution principle, which says that subclasses must fulfill all contracts of their superclass. Your class Three violates the superclass contract "foo() returns an instance of One".

Michael Borgwardt