Java, generics does not work
generics, java
Solution
`Map<Person, List<Dog>>` is not compatible with `Map<Person, List<? extends Dog>>`. In this case, the map's value type is expected to be `List<? extends Dog>`, not something that is convertible to same. But if you used `Map<Person, ? extends List<? extends Dog>>` for `f`'s parameter, it will work.
Here's a simple example involving more basic types:
Map<String, List<?>> foo = new HashMap<String, List<Object>>(); // error
Map<String, ? extends List<?>> foo = new HashMap<String, List<Object>>(); // ok
The OP asks why that behaviour occurs. The simple answer is that type parameters are invariant, not covariant. That is, given a type of `Map<String, List<?>>`, the map's value type must be exactly `List<?>`, not something similar to it. Why? Imagine if covariant types were allowed:
Map<String, List<A>> foo = new HashMap<>();
Map<String, List<?>> bar = foo; // Disallowed, but let's suppose it's allowed
List<B> baz = new ArrayList<>();
baz.add(new B());
bar.put("baz", baz);
foo.get("baz").get(0); // Oops, this is actually a B, not an A
Oops, the expectation for `foo.get("baz").get(0)` to be an `A` is violated.
Now, suppose we do it the correct way:
Map<String, List<A>> foo = new HashMap<>();
Map<String, ? extends List<?>> bar = foo;
List<B> baz = new ArrayList<>();
baz.add(new B());
bar.put("baz", baz); // Disallowed
There, the compiler caught the attempt to put an incompatible list into `foo` (via the alias `bar`). This is why the `? extends` is required.
Problem
In my opinion it should work, but it does not. Why? Source code: ``` package javaapplication1; import java.util.*; class A { public static <K,V> Map<K,V> map() { return new HashMap<K,V>(); } } class Person {} class Dog {} public class JavaApplication1 { static void f(Map<Person, List<? extends Dog>> peopleDogList) {} public static void main(String[] args) { f(A.<Person, List<Dog>>map()); } } ``` Very simple code. Compiler error: method f in class JavaApplication1 cannot be applied to give types; required: `Map<Person, List<? extends Dog>` found: `Map<Person, List<Dog>>` reason: actual arguments `Map<Person, List<Dog>>` cannot be converted to `Map<Person, List<? extends Dog>` by method invocation conversion. `Map<Person, List<? extends Dog>` is more general, so the compiler should be able to convert? Also this: `Map<Person, List<? extends Dog>> peopleDogList = A.<Person, List<Dog>>map();` does not work. `? extends Dog` means object that inherits `Dog` or `Dog`, so word `Dog` should be ok?