mark
mark

Reputation: 2931

Java - Interface Methods

Just playing around with interfaces and I have a question about something which I can't really understand.

The following code doesn't run, which is the behaviour I expect as the interface method requires the method to work for any object and the implemented method has the signature changed to only allow string objects.

interface I {
    public void doSomething(Object x);
}

class MyType implements I {
    public void doSomething(String x) {
        System.out.println(x);
    }
}

However, using the following block of code, I was shocked to see that it did work. I thought it would not work as we are expecting to return an object and the implemented method will only return a string object. Why does this work and what is the difference between the two principles here of passed parameters and return types?

interface I {
    public Object doSomething(String x);
}

class MyType implements I {
    public String doSomething(String x) {
        System.out.println(x);
        return(x); 
    }
}

Upvotes: 3

Views: 253

Answers (8)

kostja
kostja

Reputation: 61538

The principle behind this behaviour is called covariant return type. In this particular case, the overrriding type may "narrow" the originally declared parameter type.

This means that as String is subclassing Object, Object may be substituted by String.

Upvotes: 2

Christian
Christian

Reputation: 4593

From the java language specification:

Return types may vary among methods that override each other if the return types are reference types. The notion of return-type-substitutability supports covariant returns, that is, the specialization of the return type to a subtype.

So in other words, it works as you did it, but it would not work if the return type in the interface is String, and in the implementing class is Object.

Upvotes: 2

yiannis
yiannis

Reputation: 1441

This has to do with covariant return types, introduced in Java SE 5.0.
You can see more details in http://docs.oracle.com/javase/tutorial/java/javaOO/returnvalue.html

Upvotes: 2

Mohamed Jameel
Mohamed Jameel

Reputation: 602

string class is inherited from object class, so only this code works.

Upvotes: 1

DGH
DGH

Reputation: 11539

public Object doSomething(String x);

has to return something. Anything, in fact, so long as it is some type of object. So if you implement

public String doSomething(String x) {stuff}

that's fine, because it does in fact return an Object. The fact that the object it will return will always be a String is no big deal.

The reason the first example doesn't work, is because accepting only strings is more limiting than accepting any object. But returning only strings is fine.

For an analogy, let's say you got a contract to paint a building, and you're gonna hire some employees to help you out. The contract requires that you hire any painter that applies, regardless of how tall they are, but doesn't specify what color paint to use. If you only hired painters over 6 ft tall (that's the input, accepting only String instead of all Object), you'd be violating the contract. But choosing to paint with only blue paint (returning only strings) is just fine, because the contract didn't specify color, only that you must paint the building.

Upvotes: 3

maress
maress

Reputation: 3533

method signature does not take into account the return type. (Though is is an error to declare two methods with the same signature but different return type). So:

void doSomething(Object)
void doSomething(String)

Are simply two methods and none overrides or implements the other

Upvotes: 1

Mark Jeronimus
Mark Jeronimus

Reputation: 9543

The reason why the first example doesn't work and the second example does, is because function prototypes are defined by the name and all parameters only, but not the return type. In the first example, there is a difference, so the compiler thinks they are two different functions.

In the second example, the implemented function does not broaden the type, but instead specializes the type (String is a specialization of Object), so it works.

Likewise you can limit the visibility of the implemented method, but not broaden it.

Furthermore, Java has generics, which are useful in this context.

Example:

interface I<T>
{
    public void doSomething(T x);
}

class MyType implements I<String>
{
    public void doSomething(String x)
    {
        System.out.println(x);
    }
}

Upvotes: 1

Colin D
Colin D

Reputation: 5661

It works because a String is an Object.

Upvotes: 2

Related Questions