开发者

Method return type to fulfill multiple interfaces

开发者 https://www.devze.com 2023-02-05 23:28 出处:网络
Is it possible to specify a method which returns a object that impl开发者_StackOverflowements two or multiple interfaces?

Is it possible to specify a method which returns a object that impl开发者_StackOverflowements 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.


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.


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.


interface FooBar extends Foo, Bar {
    FooBar getFooBar();
}


You could return a container to provide Foo and Bar.

public class Container{
   private FooBarBam foobar;
   public Bar asBar(){
      return foobar;
   }
   public Foo asFoo(){
      return foobar;
   }
}

This way your code would not have to implement a third interface. Downside is that it is an additional layer of indirection.

As for why the generic approach does not work: there is no way to provide the type of T and the compiler can't just guess its type, so resolving T is not possible.

davin's answer looks good but also requires a public class/interface which implements Foo and Bar to work.

Update:

The problem is that the compiler does not know that the type of T should be FooAndBarImpl, it would have to guess and a guessing compiler leads to bad and unpredictable code.

Even a hack using Lists wont compile since the & operator is not supported. While it should be possible to implement it looks like generics currently don't support multiple bounds within return types.

//Does not compile expecting > after Foo
List<? extends Foo & Bar> getFooBar(){
    final List<FooAndBarImpl> l = new ArrayList<FooAndBarImpl>();
    l.add(new FooAndBarImpl());
    return l;
} 
0

精彩评论

暂无评论...
验证码 换一张
取 消