【问题标题】:Method return type to fulfill multiple interfaces - Again实现多个接口的方法返回类型 - 再次
【发布时间】:2012-09-07 09:02:07
【问题描述】:

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

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 是返回类型时? 另外,在Impl 不满足的情况下,除了null,还有什么表达式可以满足T 类型?

请注意,这个问题与this SO question 不同,虽然相似。

编辑:修正错字。

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

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

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

【问题讨论】:

    标签: java generics inheritance interface return-value


    【解决方案1】:

    原因

    <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 AB extends Object

    你可能想要的是

    <T extends A & B>
    

    其中 T 必须扩展 A 和 B。

    【讨论】:

    • 谢谢。不过问题还是一样的:)
    • 为什么您的 AB 示例会起作用?它从调用方强制要求所有返回的对象必须是 AB 的子类。另外,我的问题的第二部分是,是否有可能构建任何有效的东西(除了 null )?我的意图是保证返回的对象实现了 A 和 B。不多不少。
    • T 可以是任何扩展 A & B 和 AB 扩展 A & B 的类。
    • 在这种情况下,您需要使用演员 (T) 并注意调用者可能期望特定的类。或者你不使用泛型而使用Impl
    • 我是否可以将其解读为“否”? null 将是它可能返回的唯一值?
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-15
        • 2011-05-16
        • 2011-06-22
        • 2016-01-09
        • 2019-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多