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

时间:2012-09-07 09:02:08

标签: java generics inheritance interface return-value

今天我遇到了以下问题。考虑设置:

interface A {
    void foo();
}

interface B {
    void bar();
}

class Impl implements A,B {

    public void foo() { }
    public void bar() { }

}

class Usage {

    void worksAsParameter(){
        acceptIt(new Impl());
    }

    <T extends A & B> void acceptIt(T foo){

    }

    <T extends A & B> T returnIt(){
        return new Impl(); // <-- Compile error
    }

}

代码编译除了标记的最后一个语句外。 Eclipse给了我error: Type mismatch: cannot convert from Impl to T

我的问题是:为什么Impl在作为参数提供时可分配给T(显示在worksAsParameter但不是T是返回类型时? 另外,null除了T之外,Impl之外的哪个表达式会满足<T extends A & B> T returnIt(){ return new Impl(); // <-- Compile error } 类型?

请注意,此问题与this SO question不同,尽管类似。

编辑:修正了拼写错误。

===摘要===
我似乎误解了泛型返回类型的工作原理。我会尝试写下我对它的新认识 让我们来看看这个问题:

Usage

我最初的假设是实现类(在这种情况下为T)决定A的具体类型,但必须扩展BT 。显然,调用者/调用点可以决定Usage是什么,T必须提供可分配给T的值。但是,由于null是编译时协议,因此除了null之外不可能提供这样的值(因为它可以分配给任何东西)。 Afaik这意味着表单的任何代码都只能返回<T extends A> T returnIt(){ return x; // <-- Compile error }

{{1}}

一个相当不直观的功能,希望在不同的设置中更有用。谢谢彼得!

3 个答案:

答案 0 :(得分:4)

原因

<T extends A & B> T returnIt(){
    return new Impl();
}

不编译是T可以是任何扩展A和B的类。你碰巧知道目前只有一个可能的类,但是编译不会“知道”这个。

e.g。

class AB extends A, B { }

Usage usage = ...
AB ab = usage.<AB>returnIt(); // T is AB not Impl.

您可以使用

强制解决问题
<T extends A & B> T returnIt(){
    return (T) new Impl(); // unchecked cast warning.
}

但是更好的解决方案是

Impl returnIt(){
    return new Impl();
}

这定义了两个泛型

<T extends A, B>

T extends A以及B extends Object

您可能想要的是

<T extends A & B>

其中T必须延伸A和B.

答案 1 :(得分:1)

您可以像以下一样使用它。

   <T extends A, B> T returnIt(){
    return  (T) new Impl(); // <-- cast it to type T
  }

答案 2 :(得分:0)

您也可以执行以下操作以避免编译错误。

       <T extends A & B> T returnIt(Class<T> type) {
        return type.cast(new Impl());
    }