我试图使用java.util.Function对象作为库类的输入。
Function<? extends MyEntity, List> mapper;
public MyLibraryClass(Function<? extends MyEntity,List> mapper) {
...
}
public void aMethod(ClassExtendsMyEntity e) {
mapper.apply(e);
}行mapper.apply(e)不编译。如果我更改为使用? super而不是? extends,那么在以下代码中使用此库的客户端就会出现故障:
Function<ClassExtendsMyEntity, List> mapper = e -> e.getListObjects();
new MyLibraryClass(mapper);有人能帮我解释一下为什么要解决这个问题吗?如果有办法解决这个问题的话?
发布于 2022-08-18 15:26:15
Function<? extends MyEntity,List> mapper;这并不表示“MyEntity的任何子类都可以传递给mapper”。它说“有一些MyEntity的子类可以传递给mapper”。它可能是ClassExtendsMyEntity,可能是MyEntity本身,也可能是一些您从未听说过的疯狂类。
Function<T, S>提供了一个函数:S apply(T arg)。因为您的参数类型是? extends MyEntity,所以可以传递给mapper.apply的唯一有效参数是一个值,该值同时包含MyEntity的每个子类型,并且没有满足该条件的值。
更严格地说,Function<T, S>的第一个参数原则上是反变的,所以使用协变? extends T注释对它没有什么意义。
根据您想要的内容,有两个解决方案。如果您的函数适用于任何MyEntity,那么只需编写Function<MyEntity, List>并完全放弃泛型/通配符。另一方面,如果您希望MyLibraryClass只支持一个子类型,但是支持您所知道的一个子类型,那么您需要将它作为MyLibraryClass的一个泛型参数。
public class MyLibraryClass<T extends MyEntity> {
Function<? super T, List> mapper;
public MyLibraryClass(Function<? super T, List> mapper) {
...
}
public void aMethod(T e) {
mapper.apply(e);
}
}同样,Function的第一个类型参数原则上是反向变量,因此我们应该使用? super T将其绑定到类型参数T中。这意味着如果我有一个MyLibraryClass<ClassExtendsMyEntity>,里面的函数可能是一个Function<ClassExtendsMyEntity, List>,或者一个Function<MyEntity, List>,或者一个Function<Object, List>,因为所有这些都支持ClassExtendsMyEntity参数。有关这一原因的更多信息,请参见What is PECS。
发布于 2022-08-18 15:25:52
声明Function<? extends MyEntity,List> mapper的意思是:mapper需要一个X类型的参数,该参数是MyEntity的一个子类型。问题是,它不能说明它是哪种类型。因此,编译器无法验证传递ClassExtendsMyEntity类型实例的调用是否有效。毕竟,X可能是SomeOtherClassExtendingMyEntity。
为了解决这个问题,只需使函数类型为Function<MyEntity,List>
https://stackoverflow.com/questions/73405584
复制相似问题