For the following three scenarios :
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
}
In the 3rd case, i receive compile time failure like this for both cases where Parent object or Child object is passed to the function :
The method apply(capture#21-of ? extends Parent) in the type Function is not applicable for the arguments (Parent)
My understanding till now was : extends
does mean "is or extends" but above cases lead me to following queries:
- Why does
Function<? extends T>
is not accepting child, parent objects ? - Secondly is
Function<? super T>
accepting both child, parent objects due to the fact that parent reference can hold child objects (Base obj=new Child()
) ?
Edit:
I understand the PECS issue in collections (e.g list) like stated here since there the List<? extends Parent>
might get a reference to List<GrandChild>
. Now, if we try to add Child object
in this, it would have caused a runtime error if not caught by compiler earlier.
Similarly is the Functional interface also behaving same & how are reference maintained here ?
The functionality is explained by examples by rgettman but just want a clearer picture compared to collections.
Moreover this works, which is fine but then seems like PECS (Extends can't consume anything) shouldn't be taken literally :
<T extends Parent> void check4(List<T> myList, Function<T, String> func) {
func.apply(myList.get(0)); // compiles successfully
}