Java, generics don’t work
In my opinion, it should work, but that's not the case 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 Compilation error: method f in class javaapplication1 cannot be applied to the given type; Required: Map < personnel, list discovery: Map < person, list < dog > > reason: the actual parameter map < person, list < dog > > cannot be converted to map < person, list transform by method call
Map < personnel, list is more general, so the compiler should be able to convert?
This is also: Map < person, list > peopledoglist = A. < person, list < dog > > map(); It doesn't work? Extended dog refers to the object that inherits the dog or dog, so the word dog should be ok?
Solution
Map < person, list < dog > > and map < person, list > In this case, the value type of the map should be list instead of converting to the same thing But if you use map < person,? Extended list > it will work for the parameter of F
This is 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 asked why this behavior occurred The simple answer is that type parameters are invariant, not covariant That is, given map < string, list > The value type of the map must be completely list , Not something like that Why? Imagine if covariant types are 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
Bad, expect foo get(“baz”). Get (0) becomes a is violated
Now, suppose we do this in the right way:
Map<String,? extends List<?>> bar = foo; List<B> baz = new ArrayList<>(); baz.add(new B()); bar.put("baz",baz); // Disallowed
There, the compiler caught an attempt to put an incompatible list into foo (through the alias bar) Why? Extension is required