Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method return type to fulfill multiple interfaces

Is it possible to specify a method which returns a object that implements two or multiple interfaces?

Say we have the following interfaces:

interface FooBar {
    [Foo] & [Bar] getFooBar();
}

interface Foo {
    void doFoo();
}

inteface Bar {
    void doBar();
}

Implementors of FooBar need to provide the method getFooBar() that returns an instance of a type which fullfills Foo as well as Bar.

What I tried so far is to do it with generics:

interface FooBar {
    <T extends Foo & Bar> T getFooBar()
}

class SomeImplementor implements FooBar {
    private FooAndBarImpl fSomeField;

    public <T extends Foo & Bar> T getFooBar() {
        return fSomeField;
    }

}

Given that FooAndBarImpl is some type provided by a framework or library and implements Foo and Bar this I think should work. However, it doesn't, because "FooAndBarImpl cannot be converted to T". Why is that? The contract implied by getFooBar() is not broken as I see it.

Another solution would be to define a new interface that extends Foo and Bar and to use that as return type. I just don't see much sense in returning a empty wrapper for the fSomeField in the getFooBar() implementation.

EDIT:

Would appreciate it if someone could explain why the generics approach doesn't work. I just don't see it.

like image 808
z00bs Avatar asked Jan 20 '11 12:01

z00bs


People also ask

What if multiple interfaces have same method?

No, its an error If two interfaces contain a method with the same signature but different return types, then it is impossible to implement both the interface simultaneously. According to JLS (§8.4. 2) methods with same signature is not allowed in this case.

Can interfaces be used as return types and parameters?

No, it's not possible. The interface serves as a "binding contact" of the signatures that are available. If you want you can have the function return an Object and by that allow different implementations to return values of different types, but: It must be references, not primitives.

Can methods return interfaces?

Since an interface provides all of that, you can call methods on it, just as you can on a regular class. Of course, in order for the method to actually return some object, there needs to be some class that implements that interface somewhere.

Can a type fulfill multiple interfaces?

A type can implement multiple interfaces. In the above program, we created a Motorvehicle interface with the Mileage method and a Newq interface with the AverageSpeed method. Struct type BMW implements both the methods, hence it implements both the interfaces.


2 Answers

You can make T a class parameter:

class SomeImplementor<T extends Foo & Bar> implements FooBar {
    private T fSomeField;

    public T getFooBar() {
        return fSomeField;
    }

}

As to why your generics approach didn't work. Lets create the following two classes that implement Foo and Bar:

class A implements Bar, Foo{
   private int a;
   ...
}
class B implements Bar, Foo{
   private String b;
   ...
}
class SomeImplementor implements FooBar {
   private A someField;
   public <T extends Foo & Bar> T getFooBar() {
      return someField;
   }
}

So we should now be able to execute the following:

SomeImplementor s = new SomeImplementor();
A a = s.getFooBar();
B b = s.getFooBar();

Although getFooBar() returns an object of type A, which has no valid cast to type B (where will the String member come from?), even though B fulfills the requirement of <T extends Foo & Bar>, i.e. is a valid T.

In short, the compiler (remember, generics is a compile-time mechanism) can't guarantee that every T of type <T extends Foo & Bar> can have an assignment to it of type A. Which is exactly the error you see - the compiler can't convert the given A to every valid T.

like image 95
davin Avatar answered Nov 15 '22 16:11

davin


Another solution would be to define a new interface that extends Foo and Bar and to use that as return type.

I would say go for this option.

like image 27
Brian Avatar answered Nov 15 '22 17:11

Brian