i_am_jorf
i_am_jorf

Reputation: 54600

Java type captures for wildcards in collections

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

Answers (3)

Konstantin Solomatov
Konstantin Solomatov

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

dty
dty

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

dlev
dlev

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

Related Questions