General information about PECS
You have to think about PECS that way:
Producer extends
Let's say you have a List<? extends Number>. This list will always produce the type it is extending e.g. Number. But you don't exactly know which type, you just know the common super type of given list. Look at following example:
List<Integer> ints = Arrays.asList(1,2,3);
List<? extends Number> nums = ints;
Number n = ints.get(0); // will be 1
We are creating a list of Integers and then assign that to our other list nums. This works, because the value returned by nums will always be a Number or a subtype. In this case an Integer. You cannot add something to the list though. Because you don't know what actual list really is represented by nums. E.g. Trying to add a long to nums will fail. Because the real list only supports Integers:
nums.add(1L); // compiler error
Consumer super
This is just the other way around. Let's again say you have a list, e.g. List<?
super Number>. The list will always accept Numbers and its subtypes to be added to the list:
List<Object> objs = new ArrayList<>();
List<? extends Number> nums = objs;
nums.add(1);
nums.add(2L);
nums.add(3F);
Because the actual list is objs which can accept any Object instances above works. Though when trying to add something different than Numbers to nums the compiler will complain. Because it can't directly verify that the list really can accept the object:
nums.add("4"); // compiler error
objs.add("4"); // works still
Now the problem is that you don't really know what list you're adding your stuff to. Which makes it impossible to define a general behaviour to what should be returned when using a method like get(0). So java handles this by just returning an Object:
Object o = nums.get(0);
Which is equivalent to::
Object o = objs.get(0);
Answer to Question
So when applied to your real question. keyMapper can accept any object which type is matching T and produces any object which type matches K. Again an example might put you in the right direction:
Let's say we use String for type T and Number for type K which gives us a parameter signature like: Function<? extends String, ? super Number> keyMapper.
Now we can use the stuff i've said above to play with this signature. Lets say we define a mapper from Object to Long:
Function<Object, Long> objToLong = (Object o) -> 1L;
This mapper then can be assigned to the signature of keyMapper:
Function<? extends String, ? super Number> keyMapper = objToLong;
Because objToLong can accept a String and produces a Number. The same can be said about the valueMapper.
I hope this really long answers helps you to understand PECS better :)
Ts (hence? super T) and produce keys or values (? extends Kresp.? extends U), a canonical example of “producer extends and consumer super”…