Cast java.util.function.Function to Interface

2022-09-01 21:07:57

在这个(简化的)示例中,我可以使用引用的方法创建我的 -object,但直接强制转换不起作用。MyInterfaceapply

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


答案 1

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

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

由于 不是 的子类型,因此强制转换为 a 会抛出一个 。因此,将 a 转换为 a 的最简单方法是使用方法引用,就像您已经做过的那样:Function<String,Integer>MyInterfacefuncMyInterfaceClassCastExceptionFunction<String,Integer>MyInterface

MyInterface legal = func::apply;

答案 2

最底层的事实是,尽管所有漂亮的语法表面上都给出了这样的外观,但Java并没有采用结构类型;Liskov命名类型的可替代性规则一如既往地严格。在实际代码中,您调用 ,它返回 的某个实例,并且绝对不是 的实例。所以当你写作时Function.andThenFunctionMyInterface

MyInterface legal = func::apply;

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

MyInterface illegal = func;

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


推荐