Type safety: Unchecked cast
The problem is that a cast is a runtime check - but due to type erasure, at runtime there's actually no difference between a HashMap<String,String>
and HashMap<Foo,Bar>
for any other Foo
and Bar
.
Use @SuppressWarnings("unchecked")
and hold your nose. Oh, and campaign for reified generics in Java :)
Well, first of all, you're wasting memory with the new HashMap
creation call. Your second line completely disregards the reference to this created hashmap, making it then available to the garbage collector. So, don't do that, use:
private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
Secondly, the compiler is complaining that you cast the object to a HashMap
without checking if it is a HashMap
. But, even if you were to do:
if(getApplicationContext().getBean("someMap") instanceof HashMap) {
private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
}
You would probably still get this warning. The problem is, getBean
returns Object
, so it is unknown what the type is. Converting it to HashMap
directly would not cause the problem with the second case (and perhaps there would not be a warning in the first case, I'm not sure how pedantic the Java compiler is with warnings for Java 5). However, you are converting it to a HashMap<String, String>
.
HashMaps are really maps that take an object as a key and have an object as a value, HashMap<Object, Object>
if you will. Thus, there is no guarantee that when you get your bean that it can be represented as a HashMap<String, String>
because you could have HashMap<Date, Calendar>
because the non-generic representation that is returned can have any objects.
If the code compiles, and you can execute String value = map.get("thisString");
without any errors, don't worry about this warning. But if the map isn't completely of string keys to string values, you will get a ClassCastException
at runtime, because the generics cannot block this from happening in this case.
As the messages above indicate, the List cannot be differentiated between a List<Object>
and a List<String>
or List<Integer>
.
I've solved this error message for a similar problem:
List<String> strList = (List<String>) someFunction();
String s = strList.get(0);
with the following:
List<?> strList = (List<?>) someFunction();
String s = (String) strList.get(0);
Explanation: The first type conversion verifies that the object is a List without caring about the types held within (since we cannot verify the internal types at the List level). The second conversion is now required because the compiler only knows the List contains some sort of objects. This verifies the type of each object in the List as it is accessed.
A warning is just that. A warning. Sometimes warnings are irrelevant, sometimes they're not. They're used to call your attention to something that the compiler thinks could be a problem, but may not be.
In the case of casts, it's always going to give a warning in this case. If you are absolutely certain that a particular cast will be safe, then you should consider adding an annotation like this (I'm not sure of the syntax) just before the line:
@SuppressWarnings (value="unchecked")