Java generics and upcasting
Can somebody explain me why this
Map<String, List<String>> foo = new HashMap<String, LinkedList<String>>();
generates a type mismatch error ?
Type mismatch: cannot con开发者_StackOverflow社区vert from HashMap< String,LinkedList< String>> to Iterators.Map< String,List< String>>
Hashmap implements the Map interface, and LinkedList implements the List interface. Moreover, this
List<String> foo = new LinkedList<String>();
works...
Thanks
Because a Map<String, List<String>>
allows you to put
an ArrayList<String>
into it, but doing so would violate the type integrity of a HashMap<String, LinkedList<String>>
.
Either declare your HashMap
as a HashMap<String, List<String>>
or your variable as a Map<String, LinkedList<String>>
or Map<String, ? extends List<String>>
.
Edit
The more immediate problem is that you have imported the wrong Map
class (something called Iterators.Map
) or you have another class (or inner class rather) called Map
in the same package as this code. You want to import java.util.Map
.
In Java , Generics does not preserve subtype-covariance. So , if B is a subtype of A , Gen(B) may not be subtype of Gen(A) where Gen is some form of a Generic usage of a type.
Concretely , if LinkedList
is a subtype of List
, that does not imply that Map<String,LinkedList>
is a subtype of Map<String,List>
. As other posts have suggested , you have to use List
as your type in the HashMap
type parameters.
Fix this like the following:
Map<String, List<String>> result = new HashMap<String, List<String>>();
Pay attention that I changed LinkedList
to List
in the right side of your assignment.
You are right that LinkedList implements List. But I think that explanation of this error is not in definition of List but in definition of interface Map<K,V>
.
The left side of your expression says that you want to create Map of String and List, i.e. V
is "replaced" by List. Right side uses LinkedList. Although LinkedList implements List it does not work because the definition of Map is not something like Map<K, V extends List>
, so compiler requires exact match.
I am not sure that my description is strict enough, but anyway this is the way to right generics. Really, when you create map of list you do not care about the implementation of List, therefore say HashMap<String, List<String>>
. Only when you create instance of List care about its implementation. This will allow you to change the implementation if future without modification of other code.
Please use the Interface for the HashMap:
Map<String, List<String>> foo = new HashMap<String, List<String>>();
List<String> bar = new LinkedList<String>();
foo.put("barkey", bar);
精彩评论