Reputation: 467
I have a class using a Map as field variable:
private Map<String, ?> posts;
And in that same class I have a generic method:
public <T> void log(T message) {
if (isEnabled) {
Date time = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss:SS");
posts.put(sdf.format(time.getTime()), message);
}
}
However I get a compiler error on the posts.put statement saying:
The method put(String, capture#2-of ?) in the type Map<String,capture#2-of ?> is not
applicable for the arguments (String, T)
I'm a bit new to wildcards and generic methods so what am I doing wrong?
Upvotes: 0
Views: 170
Reputation: 213193
When you declare your Map
with an unbounded wildcard type:
private Map<String, ?> posts;
you won't be able to put anything apart from null
into it. Because ?
is a substitute for any type. Basically, your Map
is a supertype of all the instantiation of Map
with String
as a key, and value of any type. ?
can be Date, Number, Cat, Tiger, anything.
Suppose your map is instantiated like this:
private Map<String, ?> posts = new HashMap<String, Date>();
and the type parameter in your method is inferred as String
, then your put
method is doing:
posts.put(String, String);
...thus trying to add String
type where a Date
is needed. Certainly that would fail at runtime. Generic type avoids these issue by issuing a compiler error for this.
You can solve this problem by making your class itself generic, thus using the same type parameter in the method and map:
class YourClass<T> {
private Map<String, T> posts;
public void log(T message) {
if (isEnabled) {
Date time = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss:SS");
posts.put(sdf.format(time.getTime()), message);
}
}
}
Also as noted in comments, you should avoid having time
as key. Since Date#getTime()
has only milliseconds precision, so anything you put during the interval that is covered in a single milliseconds, will be stored as the same key, thus overwriting the old value for that key.
Upvotes: 4
Reputation: 2629
Map<String, ?>
doesn't mean you can put anything into that map. It means the value class is unknown. But it can be e.g. Foo or Bar. And Foo might be incompatible with any type T
, so the compiler complains. Use Map<String, Object>
instead or make your T
parameter class-level and then parametrize your map with it: Map<String, T>
Upvotes: 4