The reason you get a compiler error, for the same reason you cannot add Dog
to List<? extends Animal>
List<? extends Animal>
- you cannot call a method with a common parameter if the type of the reference variable has a wildcard of the upper bound. The type parameter of the map
value can refer to any type that matches ? extends Collection<String>
? extends Collection<String>
, possibly like HashMap<Integer, LinkedList<String>>
. You can legitimately insert this line before calling put
:
map = new HashMap<Integer, LinkedList<String>>();
The compiler does not know the exact type that is actually on the map, so at compile time it should be in put
ting a TreeSet<String>
as the value for the map, the value of which could be something like LinkedList<String>
.
In put
value in map
(except null
), you must remove the wildcard.
HashMap<Integer, TreeSet<String>> map = new HashMap<Integer, TreeSet<String>>();
As JB Nizet commented, you can still put the value of any Collection
, such as TreeSet
, if you delete the template but save the Collection
.
HashMap<Integer, Collection<String>> map = new HashMap<Integer, Collection<String>>();
(In addition, a diamond operator can simplify declarations here.)
In response to the changes added to the question:
Here you used the lower bound.
HashMap<Integer, ? super Collection<String>> map = new HashMap<Integer, TreeSet<String>>());
The type parameter can be Collection<String>
or any supertype, such as Object
. This prohibits subtypes such as TreeSet<String>
. Java generics are invariant. The only reason any variation from Collection<String>
is allowed is related to the template.
HashMap<Integer, ? super Collection<String>> map = new HashMap<>(); map.put(1, new TreeSet<String>());
This is allowed because any supertype Collection<String>
will match any subtype as an argument. After all, a TreeSet<String>
is an Object
. A TreeSet<String>
can be put
as the value of a map
, whether it be a HashMap<Integer, Object>
or HashMap<Integer, Collection<String>>
, or any other type between them. The compiler can prove type safety, so it allows you to make calls.