java使用扩展功能接口功能<?扩展父级,*>vs函数<?超级父级,*>vs函数<父级,*>
对于以下三种情况:
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
}
在第三种情况下,在父对象或子对象被传递给函数的情况下,两种情况下,我都会收到这样的编译时失败:
The method apply(capture#21-of ? extends Parent) in the type Function is not applicable for the arguments (Parent)
到目前为止,我的理解是:extends
的意思是“是或扩展”,但上述情况导致我产生以下疑问:
- 为什么
Function<? extends T>
不接受子对象、父对象李> - 其次是
Function<? super T>
同时接受子对象和父对象 由于父引用可以保存子对象(^{)李>
编辑:
我理解集合(例如列表)中的PEC问题,比如声明的here,因为在那里List<? extends Parent>
可能会得到一个到List<GrandChild>
的引用。现在,如果我们尝试在其中添加Child object
,如果编译器之前没有捕捉到,它将导致运行时错误
Similarly is the Functional interface also behaving same & how are reference maintained here ?
该功能通过rgettman的示例进行了解释,但只是希望与集合相比有更清晰的画面
此外,这是可行的,但似乎PECS(Extends不能消耗任何东西)不应该被字面理解为:
<T extends Parent> void check4(List<T> myList, Function<T, String> func) {
func.apply(myList.get(0)); // compiles successfully
}
# 1 楼答案
据编译器所知,
check3
的实际参数可能是Function<GrandChild, String>
,对于需要GrandChild
的方法来说,Parent
和Child
都不是有效的类型# 2 楼答案
根据
? extends
上限,参数function
可以是采用Parent
或Parent
子类型的任何方法。这意味着check3
可以接受一个Function<Child, String>
,而你不能将一个Parent
传递给它。这就是为什么apply
方法出现编译器错误的原因;当函数的参数类型未知时,编译器无法保证类型安全也可能存在
Parent
的任何未知子类,例如Sibling
或Grandchild
,它们也扩展了Parent
。这意味着Child
也不能是apply
的参数。function
可以是Function<Grandchild, String>
这是因为
? super Parent
是一个下限。这意味着作为参数的function
可以是Function<Parent, String>
或Function<Object, String>
。由于该函数可能需要一个Parent
或甚至一个Object
,因此可以始终将一个Parent
传递给该函数并调用apply
,因此编译在这里成功