2

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

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但不是何时返回类型?而且,除了不满足类型的情况下,还有什么表达式会满足类型?TworksAsParameterTnullTImpl

请注意,尽管相似,但此问题与此 SO 问题不同。

编辑:修正错字。

=== 总结 ===
看来我误解了通用返回类型的工作原理。我将尝试写下我对它的新理解。
让我们看一下这个问题:

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

我最初的假设是实现类(在这种情况下Usage)决定了具体的类型T,它必须扩展AB。显然,是调用者/调用站点来决定什么T是并且Usage必须提供一个可分配给的值T。然而,作为T一个编译时交易,除了null(因为它可以分配给任何东西)之外,不可能提供这样的值。Afaik 这意味着表单的任何代码都只能返回null

<T extends A> T returnIt(){
    return x; // <-- Compile error
}

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

4

3 回答 3

4

原因

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

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

例如

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。

于 2012-09-07T09:05:22.100 回答
1

你可以像下面这样使用它..

   <T extends A, B> T returnIt(){
    return  (T) new Impl(); // <-- cast it to type T
  }
于 2012-09-07T09:10:47.343 回答
0

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

       <T extends A & B> T returnIt(Class<T> type) {
        return type.cast(new Impl());
    }
于 2012-09-07T09:25:27.367 回答