Normally, I would call this a bug, but this is in the Java Standard Library.
There is a method -- java.awt.Font.getAttributes() that returns a Map<TextAttribute, ?>.
Now, this threw me for a loop because I don't know how I can insert elements into this map. After all, the parameterized type for the values we are inserting is ?, so how can we insert?
If it was fetching, I would simply store whatever I get into Object, since that is a catch all, much like the unbounded wildcard "?" is.
But this is inserting. How can I insert unless I do an unsafe cast?
Found the answer myself -- you cannot.
This is actually a clue that I was misusing the API. In my defense, the API was not very obvious. But long story short, there is a constructor that TAKES IN a
Map<TextAttribute, ?>. This means that we are PROVIDING our ownMapfor them to use. Now,Map<TextAttribute, Object>can definitely fit intoMap<TextAttribute, ?>, so that means that we are good for providing a value to pass into this constructor.And if the goal is to see what the contents of the
Mapare so that we can construct/populate our own, simply extract each object out into anObjectorvar, then do someinstanceofchecks to see what it is. From there, you can construct the proper typeVto put for yourMap<K, V>.Here is a simple code example to more clearly explain the point.
I want to insert a
TextAttributeinto ajava.awt.Font.EDIT - Special thanks as always to @Holger for showing an even better way to make this work. Here it is below.
If we look at the documentation for this method,
Font.deriveFont(Map< extends AttributedCharacterIterator.Attribute,?>), we can see that it takes in a Map whose values are of type ?. Furthermore, the documentation itself says that it "Creates a new Font object by replicating the current Font object and applying a new set of font attributes to it." So, it makes a duplicate, and then applies the changes that you passed in as a parameter to it. This is a more efficient way of doing what I described earlier.