方法返回类型以实现多个接口

时间:2011-01-20 12:48:43

标签: java generics inheritance interface return-value

是否可以指定一个返回实现两个或多个接口的对象的方法?

假设我们有以下接口:

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

interface Foo {
    void doFoo();
}

inteface Bar {
    void doBar();
}

FooBar的实现者需要提供方法getFooBar(),该方法返回满足Foo以及Bar的类型的实例。

我到目前为止尝试的是使用泛型:

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

class SomeImplementor implements FooBar {
    private FooAndBarImpl fSomeField;

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

}

鉴于FooAndBarImpl是框架或库提供的某种类型并实现FooBar,我认为这应该有用。但是,它没有,因为“FooAndBarImpl无法转换为T”。这是为什么? getFooBar()隐含的合同并没有像我看到的那样被打破。

另一个解决方案是定义一个扩展FooBar的新接口,并将其用作返回类型。我在fSomeField实现中为getFooBar()返回一个空包装时没有多大意义。

修改

如果有人可以解释为什么泛型方法不起作用,我将不胜感激。我只是没有看到它。

4 个答案:

答案 0 :(得分:14)

你可以使T成为一个类参数:

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

    public T getFooBar() {
        return fSomeField;
    }

}

至于为什么你的泛型方法不起作用。让我们创建以下两个实现FooBar的类:

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;
   }
}

所以我们现在应该可以执行以下操作:

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

虽然getFooBar()返回类型为A的对象,它没有对类型B进行有效强制转换(String成员将来自哪里?),即使B满足{{1}的要求},即有效的<T extends Foo & Bar>

简而言之,编译器(记住,泛型是编译时机制)不能保证类型T的每个T都可以赋值给它类型为<T extends Foo & Bar>。这正是您看到的错误 - 编译器无法将给定的A转换为每个有效的T。

答案 1 :(得分:2)

  
    

另一种解决方案是定义一个扩展Foo和Bar的新接口,并将其用作返回类型。

  

我会说选择这个选项。

答案 2 :(得分:2)

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

答案 3 :(得分:0)

您可以返回一个容器来提供Foo和Bar。

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

这样您的代码就不必实现第三个接口。缺点是它是一个额外的间接层。

至于为什么通用方法不起作用:没有办法提供T的类型,编译器不能只猜测它的类型,所以解析T是不可能的。

davin的答案看起来不错,但也需要一个实现Foo和Bar工作的公共类/接口。

<强>更新

问题是编译器不知道T的类型应该是FooAndBarImpl,它必须猜测并且猜测编译器会导致错误和不可预测的代码。

即使是使用Lists的hack也不会编译,因为&amp;不支持运算符。尽管应该可以实现它,但是泛型当前不支持返回类型中的多个边界。

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