【问题标题】:Using extends with functional interfaces - Function<? extends Parent, *> vs Function<? super Parent, *> vs Function<Parent, *> [duplicate]使用带有功能接口的扩展 - Function<?扩展父级,*> vs 函数<? super Parent, *> vs Function<Parent, *> [重复]
【发布时间】:2019-05-01 20:17:33
【问题描述】:

针对以下三种情况:

void check1(Function<Parent, String> function) {
    Parent p = new Parent(); 
    function.apply(p); // compiles fine
    Child c = new Child();
    function.apply(c); // compiles fine
}

void check2(Function<? super Parent, String> function) {
    Parent p = new Parent();
    function.apply(p); // compiles fine
    Child c = new Child();
    function.apply(c); // compiles fine
}

void check3(Function<? extends Parent, String> function) {
    Parent p = new Parent();
    function.apply(p); // compile time error
    Child c = new Child();
    function.apply(c); // compile time error
}

在第三种情况下,对于父对象或子对象传递给函数的两种情况,我都会收到类似的编译时失败:

类型中的方法 apply(capture#21-of ? extends Parent) 功能不适用 对于参数(父)

到目前为止,我的理解是:extends 确实意味着“是或扩展”,但上述情况导致我进行以下查询:

  • 为什么Function&lt;? extends T&gt; 不接受子对象、父对象?
  • 其次是Function&lt;? super T&gt; 接受子对象和父对象 由于父引用可以容纳子对象 (Base obj=new Child()) ?

编辑: 我了解集合(例如列表)中的 PECS 问题,如 here 所述,因为 List&lt;? extends Parent&gt; 可能会得到List&lt;GrandChild&gt;reference。现在,如果我们尝试在其中添加Child object,如果之前没有被编译器捕获,将会导致运行时错误

同样,函数式接口的行为也相同,以及如何 参考保持在这里?

rgettman 的示例解释了该功能,但与集合相比,只是想要更清晰的图片。

此外,这很好,但似乎 PECS(扩展不能消耗任何东西) 不应该按字面意思理解:

<T extends Parent> void check4(List<T> myList, Function<T, String> func) {
func.apply(myList.get(0)); // compiles successfully 
}

【问题讨论】:

    标签: java generics inheritance casting functional-programming


    【解决方案1】:
    • 为什么 Function 不接受子对象、父对象?

    您的参数function 可以是任何采用ParentParent 子类型的方法,基于? extends 上限。这意味着check3 可以接受Function&lt;Child, String&gt;,您不能将Parent 传递给它。这就是apply 方法出现编译器错误的原因;当函数的参数类型未知时,编译器无法保证类型安全。

    也可能存在 任何 Parent 的未知子类,例如SiblingGrandchild,它们也扩展了 Parent。这意味着Child 也不能是apply 的参数。 function 可以是 Function&lt;Grandchild, String&gt;

    • 其次,由于父引用可以包含子对象 (Base obj=new Child()),因此函数同时接受子对象和父对象?

    这是有效的,因为? super Parent 是一个下限。这意味着function 作为参数可以是Function&lt;Parent, String&gt;Function&lt;Object, String&gt;。因为函数可能需要Parent甚至Object,所以总是可以将Parent传递给该函数并调用apply,所以这里编译成功。

    【讨论】:

      【解决方案2】:

      check3 的实际参数 可能 例如Function&lt;GrandChild, String&gt;,据编译器所知,对于需要 GrandChild 的方法,ParentChild 都不是有效类型。

      【讨论】:

        猜你喜欢
        • 2016-12-26
        • 1970-01-01
        • 2015-05-29
        • 1970-01-01
        • 2018-11-20
        • 2019-07-12
        • 2017-06-08
        • 1970-01-01
        • 2011-06-12
        相关资源
        最近更新 更多