对于以下三种情况:
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
}
在第3种情况下,对于两者情况,如将Parent对象或Child对象传递给函数的情况,我都会收到这样的编译时失败:
类型中的方法apply(capture#21-of?扩展Parent) 功能不适用 为参数(父母)
到目前为止,我的理解是:extends
的确表示“是或扩展”,但以上情况使我提出以下查询:
Function<? extends T>
不接受子对象,父对象? Function<? super T>
接受子对象和父对象
由于父引用可以保存子对象(Base obj=new Child()
)吗?编辑:
我了解here之类的集合(例如列表)中的PECS问题,因为在那里List<? extends Parent>
可能会得到List<GrandChild>
的引用。现在,如果我们尝试在其中添加Child object
,那么如果编译器较早发现它,则会导致运行时错误。
类似地,Functional界面也具有相同的功能以及如何 此处保留了参考?
rgettman举例说明了该功能,但与集合相比,它只需要更清晰的图片。
此外,这种方法还可以,但是很好,但似乎 PECS(扩展不能消耗任何东西):
<T extends Parent> void check4(List<T> myList, Function<T, String> func) {
func.apply(myList.get(0)); // compiles successfully
}
答案 0 :(得分:1)
- 为什么Function不接受子对象,父对象?
您的参数function
可以是根据Parent
上限采用Parent
或? extends
子类型的任何方法。这意味着check3
可以接受Function<Child, String>
,而您不能传递Parent
。这就是apply
方法上出现编译器错误的原因;当函数参数的类型未知时,编译器不能保证类型安全。
还可能存在Parent
的任何个未知子类,例如Sibling
或Grandchild
,它们也扩展了Parent
。这意味着Child
也不能是apply
的参数。 function
可以是Function<Grandchild, String>
。
- 由于父引用可以容纳子对象(Base obj = new Child()),因此第二个函数同时接受子对象和子对象吗?
之所以有效,是因为? super Parent
是一个下限。这意味着function
作为参数可以是Function<Parent, String>
或Function<Object, String>
。因为该函数可能需要一个Parent
甚至是一个Object
,所以始终可以将Parent
传递给该函数并调用apply
,因此编译在此处成功。
答案 1 :(得分:0)
check3
可能的实际参数例如就编译器所知,Function<GrandChild, String>
并不适用于需要Parent
的方法,Child
和GrandChild
都不是有效类型。