将 java.util.function.Function 投射到界面

Cast java.util.function.Function to Interface

例子

在这个(简化的)示例中,我可以通过使用对 apply 的方法引用来创建我的 MyInterface-对象,但直接转换不起作用。

@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> 转换为接口吗?

由于此代码段无法编译的相同原因,它无法编译:

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

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

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

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

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

事实是,在编译时无法将 Integer::parseInt 类型设为 MyInterfaceunless assigning it 变为 MyInterface 变量。

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

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

因为 Function<String,Integer> 不是 MyInterface 的子类型,所以将 func 转换为 MyInterface 会抛出 ClassCastException。因此,将 Function<String,Integer> 转换为 MyInterface 的最明确方法是使用方法引用,就像您已经做过的那样:

MyInterface legal = func::apply;

最根本的事实是,尽管所有漂亮的语法表面上都具有这种外观,Java 并没有采用结构类型; 命名类型 的 Liskov 可替换性规则一如既往地严格适用。在您的实际代码中,您调用 Function.andThen,其中 returns 是 Function 的某个实例,绝对不是 MyInterface 的实例。所以当你写

MyInterface legal = func::apply;

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

MyInterface illegal = func;

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