Reputation: 54600
I would like to do this (minimal repro):
String key = "foo";
Object value = new Bar();
if (target instanceof Map<?,?>) {
Map<?,?> map = (Map<?,?>)target;
map.put(key, value);
...
But I am told this:
The method put(capture#25-of ?, capture#26-of ?) in the type Map is not applicable for the arguments (String, Object)
It seems like String and Object should both be okay here. My question has two parts: (1) why? And (2) how can I make something like this work?
Upvotes: 1
Views: 158
Reputation: 10332
Map<?, ?> really means, Map<? extends Object, ? extends Object> According to Java typesystem, you can only get values of type parameters specialized with ? extends wildcard from method calls. You can't pass it to the methods.
P.S. Probably you want Map<Object, Object>
Upvotes: 1
Reputation: 18998
This blog post provides the answer. In short, the compiler doesn't know if Map<?, ?>
is really a Map<String, Object>
or, say, a Map<Integer, Double>
, so it can't guarantee type safety for you.
Upvotes: 0
Reputation: 48596
The problem is that collections that use unbounded wildcards don't allow elements to be added to them. If they did, you could cast the collection to have more specific type parameters, and all of a sudden the type-safety that generics are supposed to offer is gone:
Map<?,?> map = (Map<?,?>)target;
map.put(key, value); // Not actually allowed
Map<String, String> evilMap = (Map<String, String>)map;
String barAsString = evilMap.get(key); // But it's actually a Bar!
Upvotes: 1