I wrote a class that has a map of <String, Object>
. I need it to hold arbitrary objects, but at the same time sometimes I need to cast some of those objects, so I'll do something like
HashMap<String, Object> map = new HashMap<String, Object>();
Object foo = map.get("bar");
if (foo instanceof HashMap) {
((HashMap<String, Integer>) foo).put("a", 5);
}
which gives the warning
Stuff.java:10: warning: [unchecked] unchecked cast
found : java.lang.Object
required: java.util.HashMap<java.lang.String,java.lang.Integer>
((HashMap<String, Integer>) foo).put("a", 5);
I suspect it has to do with the use of generics. I can get rid of the error using @SupressWarnings("unchecked"), but I was wondering if there was a better way to do it. Or maybe the fact that I'm getting the warning means I should reconsider what I'm doing. Is there anything I could do, or should I just use @SupressWarnings?
Use of @SuppressWarnings is to suppress or ignore warnings coming from the compiler, i.e., the compiler will ignore warnings if any for that piece of code. 1. @SuppressWarnings("unchecked") public class Calculator { } - Here, it will ignore all unchecked warnings coming from that class.
Unchecked cast means that you are (implicitly or explicitly) casting from a generic type to a nonqualified type or the other way around.
An unchecked warning tells a programmer that a cast may cause a program to throw an exception somewhere else. Suppressing the warning with @SuppressWarnings("unchecked") tells the compiler that the programmer believes the code to be safe and won't cause unexpected exceptions.
Edited (based on question clarification)
Casting to HashMap<String, Integer>
(btw, using Map
instead of HashMap
is arguably a better choice) is a different story. There's sadly no way to avoid an unchecked warning in that case due to type erasure. You can, however, use it as non-generic map:
if (foo instanceof Map) {
((Map) foo).put("a", 5);
}
You'll obviously have to cast on "gets" and you lose (perceived) type safety but there'll be no unchecked warning.
There must be more to this story. The following code:
Map<String, Object> map = Maps.newHashMap(); // or new HashMap<String, Object>();
Object foo = map.get("bar");
if (foo instanceof Widget) {
((Widget) foo).spin();
}
does NOT generate an unchecked warning for me. Nor can I imagine why would it. If you know beforehand that "bar" would always return a widget, doing this:
Widget widget = (Widget) map.get("bar");
widget.spin();
would work perfectly fine as well. Am I missing something here?
If everything else (polymorphic implementation, casts) is not applicable you can implement a heterogeneous container as described in Item 33: Consider type-safe heterogeneous containers in "Effective Java", 3rd Edition. The responsibility of the container is to ensure type-safeness.
public class Container{
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
public <T> void set(Class<T> klass, T thing) {
favorites.put(klass, thing);
}
public <T> T get(Class<T> klass) {
return klass.cast(favorites.get(klass));
}
}
The problem with your example is that you're using a HashMap<K,V>
as an entry type. This cannot be represented with a class literal as a type token. So you have to implement some form of super type token:
public abstract class TypeReference<T> {}
Your client code would then extend TypeReference for every type token needed:
TypeReference<?> typeToken = new TypeReference<HashMap<String, Integer>>{};
The type information is accessible at run-time. The container implementation has then to type check against the actual type parameters of of the type token (subclass of TypeReference).
This is a complete solution but a lot of work to implement. No collection library I know of does support containers with type references.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With