繁体   English   中英

将java.util.function.Function转换为Interface

[英]Cast java.util.function.Function to Interface

在此(简化)的例子,我可以创造我的MyInterface使用方法参照-object apply ,而是直接铸造不起作用。

@Test
public void testInterfaceCast(){
    Function<String, Integer> func = Integer::parseInt;

    MyInterface legal = func::apply; // works
    MyInterface illegal = func; // error
}

public interface MyInterface extends Function<String, Integer>{}

第二个赋值给出了编译器错误:

incompatible types: Function<String,Integer> cannot be converted to MyInterface

这个问题

我可以做一些泛型魔法,能够将Function<T, R>转换为接口吗?

MyInterface illegal = func;的原因MyInterface illegal = func; 不起作用,是因为func被声明为Function<String,Integer>类型的变量,它不是MyInterface的子类型。

MyInterface legal = func::apply; 作品如下。 你可能期望fun::apply的类型也是Function<String,Integer> ,但事实并非如此。 fun::apply的类型部分取决于编译器期望的类型。 由于您在赋值上下文中使用它,因此编译器需要一个类型为MyInterface ,因此在该上下文中, func::apply的类型为MyInterface 正是由于这个原因,方法引用表达式只能出现在赋值上下文,调用上下文和转换上下文中(参见Java语言规范 )。

由于Function<String,Integer>不是MyInterface的子类型, MyInterfacefunc强制转换为MyInterface会引发ClassCastException 因此,将Function<String,Integer>转换为MyInterface方法是使用方法引用,就像您已经做过的那样:

MyInterface legal = func::apply;

最重要的是,尽管所有漂亮的语法都表面上看起来如此,但Java并没有采用结构类型; Liskov 命名类型的可替代性规则与以往一样严格。 在你的现实代码中,你调用Function.andThen ,它返回一些Function的实例,绝对不是MyInterface的实例。 所以当你写作

MyInterface legal = func::apply;

你会得到另一个对象,它是MyInterface一个实例。 相比之下,当你写作

MyInterface illegal = func;

您试图将对现有Function的引用直接分配给illegal ,这会违反Liskov可替代性,即使它在结构上与类型匹配。 没有任何技巧可以从根本上解决这个问题; 即使Java引入了一些新的语法糖,它会使它看起来像转换,实际的语义仍然是转换 (评估到另一个实例)。

由于此代码段无法编译,因此无法编译:

Animal animal = new Animal();
Cat x = animal; //illegal assignment

即你暗示每只动物都可以成为一只猫。 编译器没有证据表明实际的超类实例在运行时确实是一只猫 ,因此会引发错误。

您必须将Integer::parseInt分配给MyInterface实例:

MyInterface func = Integer::parseInt;
MyInterface illegal = func;

因为func的类型是Function<String, Integer> (即MyInterface的超类型)。

事实是, 除非将它分配MyInterface变量, 否则 MyInterface在编译时生成类型为MyInterface Integer::parseInt

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM